In my iOS project's data model, I have an entity called Foo
that has a field image
.
I've always stored this field by using the Transformable
setting such that iOS would automatically use NSCoding
to store image.
However, I found that when I try to retrieve it, the UIImage *
that comes out is corrupt. It has CGSizeZero
size most of the time and does not contain valid data.
Has anyone also experienced this under Xcode 6 beta 4?
NB: I'm using MagicalRecord to set up the Core Data stack. I have used the so-called 'auto-migrating' Core Data stack. I Reset Content and Settings
every time I run this test on the simulator.
I have also tried to reproduce the issue on an in-memory data store (such that it's amenable to unit testing) but I cannot accurately reproduce the issue (because I haven't been able to teardown the stack and initialize it again).
I also encountered this with iOS 8, after having my app work fine with iOS 7. My problem was that I was trying to set image properties on multiple NSManagedObjects by referencing a single source image in my bundle directly; the solution is to set the properties to copies of the source image.
Details: My app lets users set an image property of players (NSManagedObjects) on a team. The image property, of course, is a transformable attribute. The user can either capture a photo or choose an avatar, which is saved as a .jpeg in my bundle. For the avatar, I was setting the property with
player.photo = [UIImage imageNamed@"avatar.jpg"];
Multiple players often had the same avatar. This wasn't a problem with iOS 7 at all, and even worked with iOS 8 as long as all the objects were in memory. But with iOS 8, the avatar images would not persist to core data after the app terminated; upon re-launch, all the images were zero-length and displayed blank space (sounds a lot like the behavior you are seeing).
The fix was to set the property to a copy of the source image with the following:
UIImage *avatar = [UIImage imageNamed:@"avatar.jpg"];
player.photo = [UIImage imageWithCGImage:avatar.CGImage];
I can see why manually performing the transformation would appear to be the solution, because you'd be setting a unique object to each image property... but the real fix (in my case, at least) was much easier.
After some investigation it turns out that in iOS 8, UIImage
now conforms to NSSecureCoding
instead of the normal NSCoding
. I suspect it's the change of underlying implementation that's causing the setting of Transformable
in our data model not to work as before.
The solution is just to take the transformation in our own hands. One such way to do this is to write our own transformer, outlined in this SO answer.