Archive for March 2014

UITextView font in IB not respected

One thing that I found to be a bit odd is that, with the latest Xcode 5 and iOS 7 SDK, if you create a UITextView inside of a UITableViewCell in Interface Builder, and change the font of the text view, it will not use your changed font in the simulator or on a device. After checking with Stack Overflow, I found that if I ticked the Selectable property for my UITextView, all of a sudden it started to respect the new font that I had selected. I am not sure if that is a bug or by design, anyone have any ideas or cite documentation one way or the other?

BTW, Happy Birthday to Leonard Nimoy. Live long and prosper.

Use NIB-based UITableViewCell properly

I like to create my complex UITableViewCell objects in their own NIB files, as it helps me keep things well organized. Unfortunately, I felt like I was not able to use NIB-based UITableViewCell properly, as the implementation of this was always a bit clunky in my opinion, since I was relegated to doing something like this:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *CellIdentifier = @"CellIdentifier";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) 
    {
        [[NSBundle mainBundle] loadNibNamed:@"MyCustomCell" owner:self options:NULL];
        cell = myCustomCell;
        self.myCustomCell = nil;
    }
 
    // do something here with the cell
 
    return cell;
}

Ugh, this was a bit messy. You had to make sure that your MyCustomCell.xib file had the file’s owner pointing back to your view controller class, and that you set up an IBOutlet to the cell.

The ability to take a project and require the latest version of iOS can be a refreshing thing, as it allows one to come up to the latest APIs and practices without having to maintain painful backward compatibility. Just such a thing happened today as I learned about the proper way to use a UITableViewCell from a NIB file.

This process involves registering a class or NIB file to work with a UITableView, hooked in through the cell identifier. To set up this registration, you would do something like this in your viewDidLoad method:

UINib *nib = [UINib nibWithNibName:@"MyCustomCell" bundle:nil];
[_theTableView registerNib:nib forCellReuseIdentifier:CellIdentifier];

(Just make sure to set up your CellIdentifier NSString variable as a global in the class or as a static in the same area that you register the NIB.) And then, the cellForRowAtIndexPath method has a little less heft to it:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
 
    // do something here with the cell
 
    return cell;
}

Because you have registered the NIB file with the cell identifier on your table view, the dequeueReusableCellWithIdentifier method knows how to either reuse or create a cell without having to explicitly do it in code. I like less heft.

BTW, Happy St. Patrick’s Day to everyone, Irish and non-Irish alike. Please be safe out there and don’t do anything dumb, which is actually a good rule to live by the other 364.24 days of the year as well.

Core Data error: The operation couldn’t be completed. (Cocoa error 19.)

Well, it has been over a year since I last had a customer with a corrupted database problem. Which means that I guess I was overdue. And what problem it is.

My customer is reporting that they now get the following error on their iPad when they try to do something with their database:

cocoa_error_19

Just in case you can’t read the text in the photo, it says:

The operation couldn’t be completed. (Cocoa error 19).

After some trouble getting the file (it is over 4 GB, not easy to e-mail), I saw a bunch of errors pop up in my debug console, including the dreaded “The database disk image is malformed”, which to me indicated that I needed to try and repair the database file. So I punched up my blog post from February of last year to try and run a repair on it.

Unfortunately, I ran into one dead end after another. I was able to dump the data out of the original database file, which produced a text file of over 8 GB. However, no matter what I tried to do to import this data back into a new database, I would end up with an empty new database.

On a lark, I decided to switch to Windows to try and fix the database file. After downloading the tools from the SQLite web site, Here is what I ended up with on my Windows computer:

C:\database>dir
 Volume in drive C is Windows7_OS
 Volume Serial Number is 50B0-39AA
 
 Directory of C:\database
 
03/14/2014  06:27 PM    <DIR>          .
03/14/2014  06:27 PM    <DIR>          ..
03/14/2014  06:16 PM     4,251,181,056 DB.sqlite
03/11/2014  11:33 AM           536,064 sqlite3.exe
03/11/2014  11:34 AM         1,388,032 sqlite3_analyzer.exe
               3 File(s)  4,253,105,152 bytes
               2 Dir(s)  240,466,235,392 bytes free

So I fired up a command prompt and tried to run some SQLite commands:

C:\database>sqlite3
SQLite version 3.8.4.1 2014-03-11 15:27:36
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> .open DB.sqlite
sqlite> .tables
.
.
Some table names listed here
.
.
sqlite> pragma integrity_check;
*** in database main ***
On tree page 1033353 cell 0: Failed to read ptrmap key=-280958431
On tree page 1033353 cell 0: 152 of 407 pages missing from overflow list starting at 1037333
Page 1037588 is never used
Page 1037589 is never used
.
.
You get the idea...
.
.
Page 1037684 is never used
Page 1037685 is never used

After going through the series of steps that I outlined in my message from last year, it appeared to process the 8 GB text file into a new database that was almost the same size as the original database file. Here was what my directory then looked like:

C:\database>dir
 Volume in drive C is Windows7_OS
 Volume Serial Number is 50B0-39AA
 
 Directory of C:\database
 
03/14/2014  06:45 PM    <DIR>          .
03/14/2014  06:45 PM    <DIR>          ..
03/14/2014  06:41 PM     8,428,761,778 dump_all.sql
03/14/2014  06:16 PM     4,251,181,056 DB.sqlite
03/14/2014  06:45 PM     4,239,932,416 DB2.sqlite
03/11/2014  11:33 AM           536,064 sqlite3.exe
03/11/2014  11:34 AM         1,388,032 sqlite3_analyzer.exe
               5 File(s) 16,921,799,346 bytes
               2 Dir(s)  227,795,791,872 bytes free

This had me feeling pretty good. Just to check, here is what I did next:

C:\database>sqlite3 DB2.sqlite
SQLite version 3.8.4.1 2014-03-11 15:27:36
Enter ".help" for usage hints.
sqlite> .tables
.
.
Some table names listed here
.
.
sqlite> select count(*) from table_name;
8716
sqlite> pragma integrity_check;
ok
sqlite> vacuum;
sqlite> .exit

It looks like success. I will have to take this data file and put it back on one of my test iPads when I get back into the office and try it out.

BTW, Happy Pi Day to everyone out there, whether you are a math person or not.

ADDENDUM: After putting the rebuilt SQLite database file back onto my own test iPad and simulator, it worked fine with no issues or cryptic error messages.

UIPopoverController arrow displays incorrectly on iOS 7

This one still doesn’t make sense to me, but I need to put it to bed and move on. When retooling an app for the latest iOS SDK, the UIPopoverController arrow displays incorrectly on iOS 7 in certain instances.

In the case where I need to display a popover controller as the result of the user tapping on a cell in a UITableView, this code has always worked fine in my iPad applications:

[thePopover presentPopoverFromRect:cell.frame inView:theTable permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];

However, after I switched over to using the iOS 7 SDK, the results look like this now:

popover_arrow_incorrect

After a bunch of investigations, I decided to try this just for the heck of it:

CGRect rect = CGRectMake(CGRectGetMaxX(cell.bounds) * 0.9, CGRectGetMidY(cell.bounds), 1.0, 1.0);
[thePopover presentPopoverFromRect:rect inView:cell permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];

With this code change, it now it looks like this:

popover_arrow_correct

And I am happy once again. Although I would still like to know why the original code does not work, if anyone has any ideas please feel free to comment. As you can see from the first image, the popover is positioned correctly (notice the vertical placement of the two line table view inside the popover, it is showing the same in both examples), it is just the arrow that is drawn incorrectly.

BTW, Happy Birthday to Tim Kazurinsky, who was great in his all-too-brief stint on Saturday Night Live, and utterly fantastic in the Police Academy series of films.