One problem with objects being so closely tied to the underlying DB in Core Data.

Why does the following code throw an exception and immediately sig kill on the second iteration at [e nextObject]:

		for (NSManagedObject *current in categories) {
			if ([lowercaseName isEqualToString:[current.name lowercaseString]] && category != current ) {
				
				// Move all the recipes.
				NSEnumerator *e = [[category valueForKey:@"recipe"] objectEnumerator];
				id object;
				while (object = [e nextObject]) {
					[(NSManagedObject *)object setCategory:current];
				}
				// Delete the category we imported.
				[moc deleteObject:category];
				
				// Reassign the current category to be returned instead.
				category = current;
				break;
			}
		}

Please note that in the above code, implied but not shown, category is an NSManagedObject and categories is an NSSet of NSManagedObjects. Also category will ALWAYS be present in categories.

The code above is intended to stop duplication of an NSManagedObject by finding out if one already exists and if it does moving it’s objects over to it.

The reason it crashes is because these objects (being NSManagedObjects) are very closely tied to the underlying database. After the first iteration through the while loop we have changed the underlying database, this change is immediately reflected in our NSManagedObject and therefore immediately reflected in the iterator. For example:

1) while (object = [e nextObject]) {

The iterator ‘e’ is attached to the managed object ‘category’, it contains 2 objects. The first of which is assigned to ‘object’.

2) [(NSManagedObject *)object setCategory:current];

The managed object ‘object’ is re-assigned away from the managed object ‘category’ to the managed object ‘current’. The managed object ‘category’ therefore now only has one object.

3) while (object = [e nextObject]) {

An exception is thrown. The NSEnumerator (actually an NSFastEnumerator something or other) can also be written in code as:

for (object in category)

Internally it behaves very very much like a for loop using pointer arithmetic. For this reason on the second loop the pointer is no longer valid as what was object no. 2 is now object no. 1. We have moved the object to another NSManagedObject and the change is reflected immediately. The contents of the while loop can be modified to anything that does not move the objects within ‘category’ and the crash goes away.

What do we do about this? Well the first thought is to work on a copy of the data. Thankfully we are given very simple tools to make copies such as:

NSSet *fishes = [[atlantic fish] copy];
NSMutableSet *fishes = [[pacific fish] mutableCopy];

Right? In this instance yes. Be aware however that this will not always solve your problems. It might give you a copy of the surface data but it does NOT give you a deep copy of the underlying objects. So fishes is not the same as atlantic but it will contain the same ‘fish’. If you follow my rather horrible example. I expect it’s influenced by the tropical fish tank and conversation I was having about Danio’s whilst I write this. The fixed code reads:

		for (NSManagedObject *current in categories) {
			if ([lowercaseName isEqualToString:[current.name lowercaseString]] && category != current ) {
				
				// Move all the recipes.
				NSSet *workingCopy = [[category item] copy];
				NSEnumerator *e = [[category valueForKey:@"item"] objectEnumerator];
				id object;
				while (object = [e workingCopy]) {
					[(NSManagedObject *)object setCategory:current];
				}
				// Delete the category we imported.
				[workingCopy release];
				[moc deleteObject:category];
				
				// Reassign the current category to be returned instead.
				category = current;
				break;
			}
		}
Posted in Programming | Tagged , | Comments Off on One problem with objects being so closely tied to the underlying DB in Core Data.

Why Fable 3’s 360 bugs piss me off but New Vegas’s PC ones didn’t.

A lot of it, possibly, can be attributed to the platform. On the PC I could, as far as possible, do things about the problems that vexed me. Although I never had a problem with slow down I did install a custom d3d dll which doubled my frame rate and got rid of most of the lag when going into VATS. I also installed a mod allowing ovens to be used to cook food, whether or not they worked was based on Luck. You could repair them with flamer fuel and a pilot light. I also only encountered 2 mission based bugs, both of which had work arounds on wikia.com.

In fable 3 though there is one bug and one feature which are greatly annoying and I am powerless to do anything about them.

– The frame rate is completely unpredictable with slow down at random times none of which seem to be related to the amount going on graphically. It drops to less than 10fps easily. It’s not a deal breaker as it doesn’t happen in combat but it’s incredibly irritating.
– More irritating than that is Jasper, it’s not his or John Cleese’s fault who is excellent. It’s rather the constant exhortation that there is something new in the sanctuary shop should I want to take a look. Every time I visit the sanctuary, which I need to do to change spells/weapons/clothes which is quite often. Shut UP! Stop telling me to buy the fucking DLC. I don’t want black dye! Lionhead, what the hell were you thinking? If people want the content, they will buy it. You have no need to ram it down our throats.

I’m also undecided on the quality of individual script dialogue. A lot of it this time seems to be self consciously poking fun at the nature of the game and games of it’s ilk in general. In the case of one quest with 3 wizards and rescuing a princess it’s obviously parody and very much part of the quest in that you are partaking in a table top rpg session. There it works well. In a quest I’ve just done involving Reaver it’s out of context, breaks immersion and smacks of laziness. I hope there is more of it but used well like the former example and not like the latter.

In more positive news, the game is excellent and a clear improvement on Fable 2. The combat is streamlined, I like the way the weapons change. In pretty much every key area that I’ve discovered so far the game is improved. I can’t comment on plot as I have not yet completed the game and it would be unfair to do so until I have.

So please Lionhead, sort out the frame rate and tone down the number of times Jasper tries to persuade me to visit the sanctuary shop. I’m not buying the DLC, in part because I already have most of it from codes provided with the pre-order (yet the game does not recognise this and would quite happily let me purchase them, which is appalling behaviour by MS Live/Lionhead whomever is responsible) and secondly I don’t accept that a few dyes are worth any MS Points at all.

Posted in Games | Comments Off on Why Fable 3’s 360 bugs piss me off but New Vegas’s PC ones didn’t.

Camera issues!

I’ve known since the start that the UIImagePickerControllerDelegate code I was using was deprecated so I’ve finally gone through and updated it. The changes were implemented to allow support for video I believe not that I’ll be needed those extensions. It’s still a good idea not to have deprecated code lying around as it will bite you eventually.
Whilst making these changes I decided it was time to allow the app to use photos taken with the camera directly. The changes are as simple as setting a property to a different value so I expected no trouble. Yet…. the app quietly terminates when the camera is opened. No obvious exception is thrown. Looking at the stack in the app crash logs on the iphone you see this:

9 libobjc.A.dylib 0x00004838 objc_exception_throw + 64
10 CoreFoundation 0x0009fd0e +[NSException raise:format:arguments:] + 62
11 CoreFoundation 0x0009fd48 +[NSException raise:format:] + 28
12 Foundation 0x00031bd6 -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] + 538
13 Foundation 0x0003192a -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] + 114
14 Cooking Companion 0x0000bb42 0x1000 + 43842
15 UIKit 0x0008cab4 -[UIViewController unloadViewForced:] + 132
16 UIKit 0x0008ca22 -[UIViewController unloadViewIfReloadable] + 10
17 UIKit 0x0008c966 -[UINavigationController purgeMemoryForReason:] + 94
18 UIKit 0x0008c896 -[UIViewController didReceiveMemoryWarning] + 10
19 UIKit 0x0008c880 -[UIViewController _didReceiveMemoryWarning:] + 8

So it get’s a memory warning and bugs out. Crap. 🙁 Performance Tool to the rescue!

— Edit —

Performance Tool Tracking Memory Allocations

Performance Tool Tracking Memory Allocations

Odd. Time to capture warning events then.

— Second Edit —

OK it even throws a memory warning for the photo picker in both the simulator and on the phone itself despite consuming less than 2MB of memory. The difference being that the photo picker doesn’t crash out. If I choose to take a photo with the camera the same memory warning is issued but it crashes. You can’t test that in the simulator as there’s no ’emulated’ camera. What on earth is going on here? It would appear that I’m not the only one with the issue and it may well be something related to how the controller is presented. For example in this case you can present it with many ‘objects’ as the parent:

The view itself.
The navigationConroller.
The tabbarController.
The main app view (wha? why would you even…)

— Final Edit —

It was other apps running on my phone causing the crash. Still doesn’t explain the memory warning being thrown on the simulator. I checked and rechecked, total memory usage for even the most intensive view was ~6MB so nowhere near the limits. The images used in recipe steps could be the most intensive but I’m working on squishing those down to reasonable resolutions (taking the iPhone 4 into account). I know I should really save them to disk and keep them out of Core Data but it’s such a hassle to manage.

Posted in Programming | 2 Comments

Progress doesn’t always feel like progress.

So many changes have been made, which doesn’t always feel like you’re getting anywhere. I’ve made it so that Recipes sent in any form are transmitted as JPEG’s at 50% quality, it seems you can set the quality level of JPEG but not PNG. This should help mitigate the possibility of a recipe being 20-30MB of data if somebody decides to create one for a cooking lesson. E.g. lots of small steps, each one illustrated.
The iPhone application has been changed into a tabbar/navbar app allowing for a permanent and separate recipe view. This meant that a lot of iPad specific code was no longer specific and could be moved to the shared classes. It also acted as an impetus to solve some of the pettier iPad specific bugs relating to that view. I also decided to adopt the iPad unified view rather than the iPhone versions recipe summary/ingredient and method split.
Many things to fix still such as image zoom, pdf generation, preview images in emailed content, ingredient/step management, category combining, whole category emailing? etc.
It also heralded the first time I’ve used the app start to finish to write in a recipe then add photographs to the steps later on. It worked fine. I also used it to record recipes from Fallout New Vegas so I could scavenge the right stuff for them in my wasteland wanderings.
A surfeit of Pumkin/Apple provided by my sister and the garden trees respectively prompted a baking of Pumpkin Pie, Apple Pie and Blackberry and Apple Pie. Lamb and Pumpkin Tagine was also cooked. Sadly time got the better of me and a lot of the pumpkin has since decided that it’s cellulose based cell walls are not, anymore generic for diovan. Shame, I was hoping to make a pumpkin chutney.

Posted in Cooking, Games, Programming | Tagged , , , , | Comments Off on Progress doesn’t always feel like progress.

I should of known it would be the relationships causing trouble.

Converting the JSON messages back into managed objects should be quite simple.  You loop around your dictionary converting stuff back.  A useful shortcut is provided by the managed object function setValuesForKeysWithDictionary.  Given that the dictionary came from a managed object in the first place we know that all of our keys should be in our object so:

2010-10-28 12:07:26.404 Cooking Companion[29814:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary managedObjectContext]: unrecognized selector sent to instance 0x8250370'

Or not. So we assume that the instance in question is inside my NSDictionary but we can’t tell which one as po will print the contents but not the addresses of the objects. We could override the NSDictionary description function to print them out but we only need to do this for debugging and there aren’t that many:

(gdb) print (id)[structureDictionary objectForKey:@"author"]
$1 = (id) 0x2a8dd68
(gdb) print (id)[structureDictionary objectForKey:@"category"]
$2 = (id) 0x841bf00
(gdb) print (id)[structureDictionary objectForKey:@"cookingtemp"]
$3 = (id) 0x8412f10
(gdb) print (id)[structureDictionary objectForKey:@"cookingtempunits"]
$4 = (id) 0x2a8dd68
(gdb) print (id)[structureDictionary objectForKey:@"cookingtime"]
$5 = (id) 0x841fe50
(gdb) print (id)[structureDictionary objectForKey:@"desc"]
$6 = (id) 0x841cbe0
(gdb) print (id)[structureDictionary objectForKey:@"gead"]
$7 = (id) 0x0
(gdb) print (id)[structureDictionary objectForKey:@"head"]
$8 = (id) 0x0
(gdb) print (id)[structureDictionary objectForKey:@"heat"]
$9 = (id) 0x841fde0
(gdb) print (id)[structureDictionary objectForKey:@"ingredients"]
$10 = (id) 0x841fa60
(gdb) print (id)[structureDictionary objectForKey:@"method"]
$11 = (id) 0x2a8dd68
(gdb) print (id)[structureDictionary objectForKey:@"photo"]
$12 = (id) 0x2a8dd68
(gdb) print (id)[structureDictionary objectForKey:@"preparationtime"]
$13 = (id) 0x841cb40
(gdb) print (id)[structureDictionary objectForKey:@"steps"]
$14 = (id) 0x841e750
(gdb) print (id)[structureDictionary objectForKey:@"style"]
$15 = (id) 0x2a8dd68
(gdb) print (id)[structureDictionary objectForKey:@"title"]
$16 = (id) 0x841f570
(gdb) print (id)[structureDictionary objectForKey:@"utensils"]
$17 = (id) 0x2a8dd68
(gdb) print structureDictionary
$18 = (NSMutableDictionary *) 0x841fd40
(gdb) print managedObject
$19 = (NSManagedObject *) 0x8421b50
(gdb) print moc
$20 = (NSManagedObjectContext *) 0x8502340
(gdb) n
2010-10-28 13:43:37.908 Cooking Companion[30053:207] -[__NSCFDictionary managedObjectContext]: unrecognized selector sent to instance 0x841bf00

Unsurprisingly it’s Category. Which is the first relationship it would have come to I suppose. Should’ve guessed it would be relationships causing trouble! 😛 So it looks like we should convert things depth first then assign.

Posted in Programming | Tagged , , | Comments Off on I should of known it would be the relationships causing trouble.

iPad rotation problems, an update.

So having created a separate test app which does not exhibit the problem I ported some of that code into my app which then starts to exhibit the issue I conclude that the problem lies within the view containing the toolbar and the table view. I’d read elsewhere that having a view controller within a view controller is a bad idea so I’m refactoring the code to:

  • Get rid of the recipe view controller.
  • Incorporate it’s toolbar and split view code into the recipedetailtableviewcontroller_ipad class.

This actually simplifies things as we have less inter class interaction messages and delegates to sling around.  However this causes one minor problem.  The iPad class inherits from a shared parent ‘common’ class which itself inherits from UITableViewController.  The problem here is that the main view is expected to be a UITableView.  In the iPad it won’t be.  So I have to recode from bottom back up.  UITableViewController is a convenience class that defines the datasource and views for us.  So we can junk it in favour of a UIViewController and code the other stuff in manually.  What this means is we need to:

  • Turn the common class into a UIViewController with the UITableView stuff built in and appropriate delegate protocols added to the .h.
  • Ensure that the iPhone class has a view defined either in code or via a nib.
  • Then the iPad class should work from the xib that was originally used.

If this doesn’t fix the view rotation issue it does give me one less view controller and view to worry about and a much simpler overall schematic for the iPad version at the expense of more manual work further down, but no less efficient as the defined UITableViewController is simply a convenience system and not voodoo, and a slightly more complicated iPad recipe view controller as it will have code in it to handle the recipe table view popover and the splitview view view view.

UPDATE:  This solved the problem.  The common class is a UIViewController with a property for a UITableView.  The iPhone version creates the table programmatically without a nib interface file:

recipeTable = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 416) style:UITableViewStyleGrouped];

The iPad version uses the same nib file as before but with the UITableViewController deleted.  Right back to emailing recipes around the place.

Posted in Programming | Tagged , , , | Comments Off on iPad rotation problems, an update.

Some quick math about the app store.

If we image the following, slightly unrealistic, scenario:

1) That I’d like to recoup the cost of my Mac.
2) That I’d like to recoup the cost of the developer program for 1 year.
3) That I’d like to draw, retrospectively, a moderate salary for the time it took which is let’s say 3 months.

Then we have:

Mac : £1700
Developer Program : £59
Salary Per Month : £1500
Total : £6259

Apple take 30% of the Applications retail cost so I need to inflate that sum to arrive at the total value of sales such that I receive that much in return:

A * 0.70 = £6259
£6259/0.70 = A
A = £8941.50

If we assume I price it at the lowest possible price which is £0.59 then we need to sell ~15200 copies. 😛

Posted in Miscellany | Tagged , , | Comments Off on Some quick math about the app store.

A few iPad differences/bugs to squish.

Whilst working on the code to email recipes as PDF’s and whatnot I’ve had the opportunity to give the iPad version of the code a thorough going over. I’ve encountered a few bugs. Some are technically present in the iPhone version but are not a consideration due to the interface.

You can repeatedly add recipes in the iPad version without leaving the last one. This is not possible on the iPhone due to the recipe screen occupying the whole display so you have to navigate out of process by hitting cancel or save before you can get to the add button again. Which is how it should be in a navigation app on the iPhone. However on the ipad the recipe list view is always present and thus so is the add recipe button. It’s possible to continuously add blank recipes with no information. Driving this ‘feature’ to destruction eventually meant the core data db was so buggered I had to delete it. That’s a simple enough fix with a delegate call to disable the button until one is saved/cancelled.

Another seems quite particular to the iPad. Testing the rotation of the device in all possible application states lead to a strange discovery. In portrait mode the application behaves fine including rotation at all stages. In landscape mode, regardless of when the orientation into that state was applied, a strange thing happens in two of the dialogs. There are three modal dialog boxes in the ipad version. One to add a new category and two in the recipe view for adding ingredients and steps. The latter two cause a bizarre problem in landscape,when they are closed via cancel or save.  The parent recipe view rotates 90 degrees.  After this has occurred further rotations also cause the view to rotate so it never again appears in the correct orientation.  This appears to affect the view containing both the recipe and the toolbar although it’s hard to tell if the toolbar has truly rotated or whether it has just be obscured by the recipe view.

I’ve noted people complaining about this issue but their solutions do not appear to resolve my problem.  One was attempting to force his application in landscape mode so his solution was trivial and others discovered they had not implemented shouldAutorotateToInterfaceOrientation everywhere.  So far so confused and a bit pissed off as this really needs to be solved.  Won’t get approved with such UI weirdness present.

Posted in Programming | Comments Off on A few iPad differences/bugs to squish.

That’s quite enough of that for the day.

So in conclusion we have established the following:

1) Recipes with all the photos embedded could be quite epic in size. 10-20 MB perhaps.
2) Bluetooth will only send around 100kB in one call.
3) You can implement a state machine at each end to track data sent and re-assemble it plus retransmit lost packets.

Thus to proceed tomorrow I would like to:

1) Alter recipe step rendering code to cleanly omit the image if it’s not present. Thus it will need to cleanly include an icon in edit mode to allow one to be added.
2) Allow sending of recipes via bluetooth with images removed, step 1) implemented first.
3) Allow sending of full recipes via email.
4) Alter image manipulation code to ensure it doesn’t try to shrink images that are already smaller than it’s parameters.
5) If all the above is complete implement code to allow preview images to appear inside emails.
6) If that is complement implement code to allow pdf generation and thus printing.

Posted in Programming | Comments Off on That’s quite enough of that for the day.

Should have read the Gamekit docs.

Damnit. Got everything working and then got errors during the first tests:

2010-10-19 18:34:14.969 Cooking Companion[1369:207] AGPSessionBroadcast failed (801c0001)

It would appear that I’m limited to 95kB. Sadly I am trying to send:

(gdb) print (NSUInteger)[data length]
$4 = 387339

I would expect that 381000 bytes of that are my UIImage data. So I have a few choices. Firstly I’m going to stop storing full sized images but limit them to a more conservative 640 pixels tops. This seems reasonable for the iPhone 4’s 960×640 and the iPad’s 1024×768 resolution. So that restricts it to:

(gdb) print (NSUInteger)[data length]
$5 = 895035

Right. Odd isn’t it? Run my images through this function to limit the size:


	CGSize size = selectedImage.size;
	CGFloat ratio = 0;
	if (size.width > size.height) {
		ratio = 640.0 / size.width;
	} else {
		ratio = 640.0 / size.height;
	}
	CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height);
	
	UIGraphicsBeginImageContext(rect.size);
	[selectedImage drawInRect:rect];
	recipe.photo = UIGraphicsGetImageFromCurrentImageContext();
	UIGraphicsEndImageContext();

And they get much larger. A quick test using an empty view based application with a jpeg from my digital camera:

- (void)viewDidLoad {
    [super viewDidLoad];
	
	UIImage *jpeg = [UIImage imageNamed:@"P1040367.jpg"];
	NSData *original = UIImagePNGRepresentation(jpeg);
	
	CGSize size = jpeg.size;
	CGFloat ratio = 0;
	if (size.width > size.height) {
		ratio = 640.0 / size.width;
	} else {
		ratio = 640.0 / size.height;
	}
	CGRect rect = CGRectMake(0.0, 0.0, ratio * size.width, ratio * size.height);
	
	UIGraphicsBeginImageContext(rect.size);
	[jpeg drawInRect:rect];
	UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
	UIGraphicsEndImageContext();
	NSData *resized = UIImagePNGRepresentation(image);
	NSLog(@"Finito");
}

From debugging:

(gdb) print (CGSize)[jpeg size]
$2 = {
  width = 2448, 
  height = 3264
}
(gdb) print (CGSize)[image size]
$3 = {
  width = 480, 
  height = 640
}
(gdb) 

So it gets resized. What about the data length?

(gdb) print (NSUInteger)[original length]
$4 = 10572117
(gdb) print (NSUInteger)[resized length]
$5 = 639538

What’s interesting here is that the original jpeg is only 2.4 MB yet my NSData representation is 10MB. Not a good thing to transmit, it also makes me think the images I was using earlier were small and I was unwittingly making them much larger.

Posted in Miscellany, Programming | 1 Comment