I am implementing MKMapView based application. In that I am using an observer when we tap on a pin. the observer is code is follows,
[annView addObserver:self
forKeyPath:#"selected"
options:NSKeyValueObservingOptionNew
context:#"ANSELECTED"];
It is working as expected, but some time it is getting exception 'EXC_BAD_ACCESS'. My log is as follows and it is showing me a leaking memory. Do I need to release the server?. If I ? then where should I release this?
An instance 0x1b21f0 of class MKAnnotationView is being deallocated
while key value observers are still registered with it. Observation
info is being leaked, and may even become mistakenly attached to
some other object. Set a breakpoint on NSKVODeallocateBreak to stop
here in the debugger. Here's the current observation info:
<NSKeyValueObservationInfo 0x11e5f0> (
<NSKeyValueObservance 0x1b1da0: Observer: 0x120f70, Key path: selected, Options: <New: YES, Old: NO, Prior: NO> Context: 0x2b588, Property: 0x1acaa0>
It is working as excepted, but some time it is getting exception 'EXC_BAD_ACCESS'. My log is as follows and it is showing me a leaking memory. …
An instance 0x1b21f0 of class MKAnnotationView is being deallocated while key value observers are still registered with it.
That's the opposite of a leak. It is being deallocated; a leak is when an object will never be deallocated.
The problem is that it's being deallocated while something else is still observing it. Anything that's still observing this object may also send it other messages later; when it does, those messages will go to a dead object (causing the crash you saw, which happened after that message) or to a different object.
If the object that is observing the MKAnnotationView is owning it and releasing it, it needs to remove itself as an observer before releasing it. If it does not own it, it probably should.
You have to stop observing the annotation view before you release it:
[annView removeObserver:self forKeyPath:#"selected"];
I know that it's quite old but I see that this code is used a lot on stackoverflow and in other repositories, and here is a solution to the problem.
You should create an NSMutableArray ivar in your view controller class in order to store a reference to your annotations view:
MyMapViewController <MKMapViewDelegate> {
NSMutableArray *annot;
}
Initialize it in your viewDidLoad and in your - (MKAnnotationView *) mapView:(MKMapView *)theMapView viewForAnnotation:(id <MKAnnotation>) annotation
you should add the MKAnnotationView to the mutable array itself right before the annView addObserver code:
if(nil == annView) {
annView = [[MyAnnotationView alloc] initWithAnnotation:myAnnotation reuseIdentifier:identifier];
[annot addObject:annView];
}
[annView addObserver:self
forKeyPath:#"selected"
options:NSKeyValueObservingOptionNew
context:(__bridge void *)(GMAP_ANNOTATION_SELECTED)];
Then, in your viewDidDisappear method you can iterate the array and remove manually all the observers:
//remove observers from annotation
for (MKAnnotationView *anView in annot){
[anView removeObserver:self forKeyPath:#"selected"];
}
[annot removeAllObjects];
[super viewDidDisappear:animated];
Related
In my application, I observe the properties of a managed object. A change may lead to adjustments in some of its other properties, so the managed object itself receives a message of a changed property. These changes happen through bindings that are set up in the Interface Builder.
I have the following method in the implementation of the managed object:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ( !processingChange )
{
processingChange = YES;
*** DO STUFF TO THIS MANAGED OBJECT'S PROPERTIES ***
[self.managedObjectContext processPendingChanges];
processingChange = NO;
return;
}
}
The processingChange boolean is there to avoid an endless "notification loop", but it is not working as I expect (plus it looks like a real dirty hack).
There must be another way to do this. Any suggestions?
use MOMs' setPrimitiveValue:forKey: it doesnt generate KVOs
I think no need to send the notification "by hand", take a look: https://developer.apple.com/library/mac/#documentation/cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i
The observeValueForKeyPath:ofObject:change:context: method is
automatically invoked when the value of an observed property is
changed in a KVO-compliant manner, or if a key upon which it depends
is changed.
Maybe this is even the mistake?
I keep running into this issue wherein I'd like to trigger an event (void) during a scheduled update or tick method - but only trigger it once. The problem is that it gets triggered every time update/tick gets called (each frame). Depending on what method is being called, this slows down the game and occasionally crashes (e.g. addChild already added). I've used a BOOL (e.g. eventTriggered) before to try to handle this situation but am wondering if that is the only and/or best way?
If you're using cocos2d 2.0 just use:
[self scheduleOnce:#selector(yourMethod:) delay:3.0f];
In all other cases simply unschedule the scheduled selector:
-(void) yourScheduledMethodThatShouldOnlyRunOnce:(ccTime)delta
{
[self unschedule:_cmd];
// do stuff once
}
If it's a custom method you need to have some condition that fires the method call, for example:
-(void) update:(ccTime)delta
{
if (runThisNowButOnlyOnce)
{
runThisNowButOnlyOnce = NO;
[self runThisNowButOnlyOnceMethod];
}
}
You just need to figure out when and where to set runThisNowButOnlyOnce to YES. Also don't forget to add it as an ivar to the #interface.
I'm curious to know what the best way is to create a new NSManagedObject in RestKit 0.20? Currently my code looks something like this:
#pragma mark - navigation buttons
- (void)createButtonDidTouch
{
// create new album object
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
NSManagedObjectContext *parentContext = RKObjectManager.sharedManager.managedObjectStore.mainQueueManagedObjectContext;
context.parentContext = parentContext;
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:#"Album" inManagedObjectContext:parentContext];
Album *newAlbum = [[Album alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:context];
// pass object to create view to manipulate
AlbumCreateViewController *createViewController = [[AlbumCreateViewController alloc] initWithData:newAlbum];
createViewController.delegate = self;
createViewController.managedObjectContext = context;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:createViewController];
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentViewController:navController animated:YES completion:nil];
}
#pragma mark - create view controller delegate
- (void)createViewControllerDidSave:(NSManagedObject *)data
{
// dismiss the create view controller and POST
// FIXME: add restkit code to save the object
NSLog(#"save the object...");
NSDictionary *userInfo = [KeychainUtility load:#"userInfo"];
NSString *path = [NSString stringWithFormat:#"/albums/add/%#/%#", userInfo[#"userID"], userInfo[#"apiKey"]];
[RKObjectManager.sharedManager postObject:data path:path parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
operation.targetObject = data;
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"create album error: %#", error);
}];
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)createViewControllerDidCancel:(NSManagedObject *)data
{
// dismiss the create view controller
NSLog(#"delete the object...");
// FIXME: add restkit code to delete the object
[self dismissViewControllerAnimated:YES completion:nil];
}
I'm also curious to know what my responsibilities are for saving / deleting this object. If I POST to the server via RestKit is the managed object context saved?
What if I decide to cancel this creation process — what's the preferred way to delete this object?
Basically how much is RestKit doing for me, and what should I make sure I'm doing. I haven't found much documentation on this and would like to be clear on it.
When you initialize an RKManagedObjectRequestOperation for a given object, RestKit will obtain a permanent object ID for that object and then create a child managed object context whose parent context is the context the object is inserted into. The operation then executes the HTTP request to completion and obtains a response.
If the response is successful and the mapping of the response is successful (note that the mapping occurs within this private child context), then the private child context is saved. The type of save invoked is determined by the value of the savesToPersistentStore property (see http://restkit.org/api/0.20.0/Classes/RKManagedObjectRequestOperation.html#//api/name/savesToPersistentStore).
When YES, the context is saved recursively all the way back to the persistent store via the NSManagedObjectContext category method saveToPersistentStore (see http://restkit.org/api/0.20.0/Categories/NSManagedObjectContext+RKAdditions.html).
When NO, the context is saved via a vanilla [NSManagedObjectContext save:] message, which 'pushes' the changes back to the parent context. They will remain local to that context until you save them back. Keep in mind that managed object context parent/child hierarchies can be as long as you create within the application.
If the HTTP request failed or there was an error during the mapping process, the private context is not saved and the operation is considered failed. This means that no changes are saved back to the original MOC, leaving your object graph just as it was before the operation was started (except the object being sent, if temporary, now has a permanent object ID but is still unsaved).
The way you do it should works (calling each time the MOC in each of your VC), but is not "recommended".
What Apple suggests, just like any Core Data app, is the "pass the baton" style.
Nested contexts make it more important than ever that you adopt the
“pass the baton” approach of accessing a context (by passing a context
from one view controller to the next) rather than retrieving it
directly from the application delegate.
See here:
http://developer.apple.com/library/ios/#releasenotes/DataManagement/RN-CoreData/_index.html
As for your second question, RestKit should manage saving/updating your Core Data stack upon success of your api calls if everything is well mapped/setup.
From blake the RK creator:
if you POST or PUT a Core Data object, RK obtains a permanent object
ID for it and then creates a secondary managed object context, fires
the request, and maps the response (if possible). if the response and
the mapping are successful, it will either save it back to the parent
context or all the way back to the persistent store (i.e. into SQLite)
based on the value of the savesToPersistentStore.
I want override all methods of a subclass automatically on xcode, for example I have a class extended of UiViewControler, how I override all methods of UiViewController on xcode to be more or less well:
- (id) init
{
return [super init];
}
My intention with this is to log all methods to see when they are called, then my methods will be more or less well
- (id) init
{
[self log];
return [super init];
}
where log is as follow method:
-(void) log
{
NSLog(#"%#",[(NSString *) (NSArray *) [NSThread callStackSymbols][1] componentsSeparatedByString:#"-["][1]);
}
thanks a lot!
In this case you don't have to do anything. If you don't provide an implementation, then the superclass's implementation will be used.
Edited after the question was edited
If you put the log statement in the superclass's implementation then it doesn't matter what you do with your own initialiser.
Why?
One of the many conventions in Cocoa is that each class has a designated initialiser. All the other designated initialisers then call this initialiser. And when you subclass the class, then you create a new designated initialiser for the new class, and as part of the initialisation - this calls the superclass's designated initialiser.
Which is why you see NSObject subclass initialisers calling [super init], because NSObject's designated initialiser is init.
So, just call your logging method in the designated initialiser of your class, and as long as you follow the above convention, this initialiser will always be called by a subclass, and so your logging method will always be called.
I have a singleton as class method:
+(WordsModel *) defaultModel{
static WordsModel *model = nil;
if (!model) {
model = [[[self alloc] init] autorelease];
}
return model;
}
What happens with the static reference to model inside the method? Will it ever get released?
Not only will it get released (because you sent it an -autorelease message), your next attempt to use it will probably lead to a crash because the model pointer wasn't set to nil when the object was released. So, it will then point to memory that's either garbage, or (if that memory has been re-used) to a different object than the one you expected.
It won't work as you are autoreleasing your instance of your class...
On the next runloop, it will be released...
Take a look at the standard singleton patterns:
http://www.cocoadev.com/index.pl?SingletonDesignPattern
The static instance should be a global variable, that will be freed when your app exits...