awakeFromFetch with non-managed property - objective-c

I have an NSManagedObject subclass with some image data in an NSData property (imageData), which is automatically persisted. After loading the data from the network I also set a custom NSImage property (image) with an image created from the data.
The problem is that if the object is a fault, awakeFromFetch is not called when I access the image property, since it is not handled by Core Data. I can of course override the image accessor and make sure the properties are loaded (by accessing imageData) but it would be nice if there was a way to have awakeFromFetch invoked as normal. Any suggestions?

As per TechZen's suggestion, I now execute the fetch request with returnsObjectsAsFaults set to NO. It's of course not ideal to pull all data from the cache each time the object is fetched, but in my case I always use the data immediately so it's acceptable.

You seem to want to do two contradictory things, you want the main entity to remain fault but be able to access its attributes. You cannot do that. A fault by definition has not attributes/properties because it is just a placeholder in the object graph. If you want your main object to remain a fault, you should move the UIImage to its own entity and link it to the main object. You should then be able to walk the object graph to obtain the UIImage without triggering the loading of the main object's fault placeholder.

Related

KVO with NSPrivateQueueConcurrencyType

I would like to determine if an attribute changed in core data and update my UI. The attribute may change as the result of a background fetch running in a managed object context of type NSPrivateQueueConcurrencyType.
I added a listener: [myCoreDataEntity addObserver:self forKeyPath:myCoreDataAttribute options:NSKeyValueObservingOptionNew context:nil]
But the event never fires. Any idea why? The object is changed in another context - could this be the reason? (When a save: is done on the parent context, nothing still fires).
I can use manual KVO, but since the object has not been saved yet to the parent context, refreshing the UI does not work since it is point at the context in NSMainQueueConcurrencyType when the object was changed in a context associated with NSPrivateQueueConcurrencyType
You're not getting notifications because you're observing the wrong object. The NSEntityDescription never changes at run time. It's a representation of the way the entity was defined in the data model. Instances of NSManagedObject that use the entity description can and do change at run time, though. If you want to know whether an attribute changed on a specific managed object, you need to observe that specific object.
If you need to get notified any time any managed object changes the value for that attribute, your best option is to write a custom setter for that attribute and handle it there. You might also find NSManagedObjectContextObjectsDidChangeNotification useful, but that will fire for any attribute change.
Assuming that myCoreDataEntity in your example is a managed object, the issue is that automatic external change notifications are [disabled by Core Data for managed objects] for modeled properties1:
NSManagedObject disables automatic key-value observing (KVO) change notifications for modeled properties, and the primitive accessor methods do not invoke the access and change notification methods. For unmodeled properties, on OS X v10.4 Core Data also disables automatic KVO; on OS X v10.5 and later, Core Data adopts to NSObject’s behavior.
You can turn them on for specific properties, or for all properties in your managed object subclass or in a category on the managed object subclass:
Single property:
- (BOOL) automaticallyNotifiesObserversFoMyCoreDataAttribute {
return YES;
}
All properties (Not recommended):
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
return YES;
}
The reason it does not send out automatic change notifications is primarily performance. Automatic change notifications do add some overhead, though on recent hardware it's fairly minor, even when working with thousands of objects. As always, profile to see what works for you.

MVC: Controller keeps array of model objects or view objects?

I have a view controller placeViewController which pulls in a bunch of Place objects, and from these loads and populates a matching bunch of PlaceView objects which are then displayed as subviews to its main view.
I need to update these views periodically which requires information from the model and other places to be pushed into the views
How should I properly structure this?
Keep an array of Place objects and give the model a PlaceView property to store pointers to the views
Keep an array of PlaceView objects and give the view a Place property to store pointers to the places
Keep both arrays and use a lot of indexOfObject objectAtIndex to jump between them
Some other way??
I need to update these views periodically which requires information
from the model and other places to be pushed into the views
You should really focus on an ObserverPattern. Yours views register to "notifications", and when changes are made, your registered views are notified.
http://en.wikipedia.org/wiki/Observer_pattern
You still can use NSNotificationCenter, but it will not futfill your needs since you need yours views make update per Place object (paired like a dictionary). So i recommend you to implement your own.
It will loose coupled because your controller will just only make glue between the observer and your views, and all the "logic" will be handled by the observer.
Well basvk got the answer in his comment but hasn't posted an actual answer for me to mark correct.
So here it is: "I would create a NSMutableArray with PlaceView objects. And the PlaceView class holds a #property Place *place"

How to store CGContext state in a NSMutableArray?

I am new to the CGContext world.
I need to create a stack of CGContext(s) in a NSMutableArray.
I have a valid PDFContext created with UIGraphicsBeginPDFContextToData
I'm passing this context to a method as an argument
-(void) drawTo:(CGContextRef) context{}
First I identify the current context with:
CGContextRef curCon = context;
NSLog value:
context:<CGContext 0x6b79d60>
Then I attempt to make a copy of the current context:
CGContextRef conCopy = UIGraphicsGetCurrentContext();
Then I add it to my NSMutableArray:
[myMutableArray* addObject:(id)conCopy];
Then I list the content of the NSMutableArray:
after an object added:<__NSArrayM 0x6b7e850>(<CGContext 0x6b79d60>)
And I see that the added value is the same context as originally sent to this method as an argument and not the copy.
What am I missing here ? Or perhaps it's not possible to store the status of current context in a NSMutableArray ? I understand that paths would not get saved, that's fine. I need to save anything and everything about the current context that can be saved.
Thank you!
You can't do this directly. But what's the real problem you're trying to solve? CGContextSaveGState() does what you're asking for, but only within the scope of the current context. CGLayer can effectively create contexts that you can carry around (though you still can't serialize them).
If your real goal is to save non-path state in a copyable form, then you can create a copyable object by calling all the CGContextGet... methods and storing their results. Then you can call CGContextSet... on them to make a new context. It's tedious, but should not be difficult. (Though it does raise the question of why. It feels like a very odd thing to be doing.)
UIGraphicsGetCurrentContext does no create a copy. The returned context is there one you created using UIGraphicsBeginPDFContextToData.

How to stop Core Data application from loading managedObjectContext automatically?

I am building a core data application that checks for a saved user login upon launch and sets up the model, store, coordinator and context afterwards. The only problem I have is that as soon as the user clicks on any view in the interface, the application tries to get the managedObjectContext causing an exception seeing as I haven't created the stores yet.
Is there any way to stop it from doing this?
Cheers.
If you're using the Coredata boiler plate stuff provided by Apple, you will notice the managedObjectContext object is loaded lazily when its property is accessed.
Simply tell your view controller to access the context via its property (i.e. self.managedObjectContext) instead of accessing the variable directly, and the context, object model and persistent store coordinator will be created appropriately.
PS: This is just a guess as you didn't post any of your related code here.
Why are you showing views that depend on the managed object context without either creating it already or arranging for it to be created on access?
The usual pattern is to have your managed object context getter look something like this:
- (NSManagedObjectContext *)managedObjectContext {
if (!_managedObjectContext) {
// create context, and store it in _managedObjectContext
}
return _managedObjectContext;
}
(in this code, _managedObjectContext is an ivar in the class to hold the context). That way the context gets created automagically when needed. Apple's standard sample code does just this for you.

Core Data: When and where are Entities loaded in the first Place?

I have a question about Core Data. When starting my appliction, when is my data (which is stored automatically by Core Data) loaded into the NSArrayControllers? I want to modify it in the first place before the user can interact with it.
To be more specific: I have an NSArrayController for the entitity Playlist. Before the user can add new playlists or interact with the app at all, I want to modify the playlists programmatically. I tried windowControllerDidLoadNib: in my NSPersistentDocument (MyDocument.m) and awakeFromNib both in my NSPersistendDocument and the NSArrayController, but when I check in these methods with [[myArrayController arrangedObjects] count] I get 0 as result (the array controller's content is empty).
However, I actually have data stored and it is displayed to the user. I just do not know when and where I can modify it in the first place.
Thank your for any help.
Data is never "loaded" into the NSArrayController. The array controller is not an array itself. It does not contain or otherwise store data.
Instead, the array controller queries the object it is bound to for specific pieces of data only when that specific data is needed. This is especially true of Core Data in which managed objects are only fully instantiated when their attributes are accessed. The array controller moves data from an array type data structure to another object (usually an UI element.)
If you want to modify an existing store before it displays in the UI, you need to process the data before the array controller used by the UI is even initialized. If you're using NSPersistentDocument, then you can override readFromURL:ofType:error: to fetch and modify all your objects when the document is first opened. Alternatively, you can override the window controller's windowWillLoad or showWindow methods.
Regardless of where you do it, you must fetch all the managed objects you want to modify. You could programmatically create an array controller to do this but a fetch request is easier to micro manage if you have a large number of objects to modify.
You could try observing the "arrangedObjects" keypath of the controller and adding some logic to work that your array controller has been populated for the first time.
Another possible hook is implementing the awakeFromInsert/awakeFromFetch methods of your managed objects.