MKMapView crash on removeAnnotation - mapkit

I'm trying to remove annotaenter code heretion some a MKMapView but am crashing on this line:
[self.mapView removeAnnotation:p];
p is an object that implements the MKAnnotation protocol and already has an annotation on that map.
This is the message I'm getting when I crash:
objc[46534]: FREED(id): message release sent to freed object=0x4319640
Program received signal: “EXC_BAD_INSTRUCTION”.
(gdb)
The backtrace looks like so:
(gdb) bt
#0 0x951424b4 in _objc_error ()
#1 0x951424ea in __objc_error ()
#2 0x951407dc in _freedHandler ()
#3 0x000786f6 in -[NSConcreteMapTable removeObjectForKey:] ()
#4 0x00003970 in -[MapViewController horizontalPickerVC:toggleGroup:enabled:] (self=0x4322a00, _cmd=0x24349, picker=0x43248c0, groupId=3, enabled=0 '\0') at /Users/me/Desktop/FanMapper/fanmapper/Classes/MapViewController.m:183
Any ideas?

Turns out my MKPinAnnotationView was set to autorelease.

Related

NSRunLoop runMode does not always process dispatch_async

I'm trying to get a better understanding of queues and how they work. This snippet is to test their behaviour:
- (void)dispatchQueueTest
{
NSLog( #"Begin test on %# thread", [NSThread isMainThread] ? #"main" : #"other" );
dispatch_semaphore_t s = dispatch_semaphore_create(0);
dispatch_async( dispatch_get_main_queue(), ^{
NSLog( #"Signalling semaphore" );
dispatch_semaphore_signal(s);
});
NSLog( #"Waiting for worker" );
while( dispatch_semaphore_wait( s, DISPATCH_TIME_NOW ) ) {
NSDate* timeout = [NSDate dateWithTimeIntervalSinceNow:10.f];
// Process events on the run loop
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout];
}
dispatch_release(s);
NSLog( #"All sync'd up" );
}
As would be expected it produces this in the log:
Begin test on main thread
Waiting for worker
Signalling semaphore
All sync'd up
What is strange is that if this code is called from, say, - (void)viewDidAppear:(BOOL)animated of a UIViewController, then it changes behaviour. Specifically it deadlocks with the following log:
Begin test on main thread
Waiting for worker
My question is why does NSRunLoop runMode not process the block sent via dispatch_async in this situation but it does in others?
I have a project where I push a PlayerNameEntryViewController onto a navigation controller. I put a breakpoint in -[PlayerNameEntryViewController viewDidAppear:]. Here's the stack trace when the breakpoint was hit:
#0 0x0002d3d3 in -[PlayerNameEntryViewController viewDidAppear:] at /Volumes/b/Users/mayoff/t/hotseat2/hotseat2/Home/PlayerNameEntryViewController.m:39
#1 0x00638fbf in -[UIViewController _setViewAppearState:isAnimating:] ()
#2 0x006392d4 in -[UIViewController __viewDidAppear:] ()
#3 0x006395d7 in -[UIViewController _endAppearanceTransition:] ()
#4 0x00648666 in -[UINavigationController navigationTransitionView:didEndTransition:fromView:toView:] ()
#5 0x007ee90e in -[UINavigationTransitionView _notifyDelegateTransitionDidStopWithContext:] ()
#6 0x007eec17 in -[UINavigationTransitionView _cleanupTransition] ()
#7 0x007eec86 in -[UINavigationTransitionView _navigationTransitionDidStop] ()
#8 0x005a2499 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] ()
#9 0x005a2584 in -[UIViewAnimationState animationDidStop:finished:] ()
#10 0x00497e00 in CA::Layer::run_animation_callbacks(void*) ()
#11 0x02e86515 in _dispatch_main_queue_callback_4CF ()
#12 0x015fe833 in __CFRunLoopRun ()
#13 0x015fddb4 in CFRunLoopRunSpecific ()
#14 0x015fdccb in CFRunLoopRunInMode ()
#15 0x01acd879 in GSEventRunModal ()
#16 0x01acd93e in GSEventRun ()
#17 0x00571a9b in UIApplicationMain ()
#18 0x00002461 in main at /Volumes/b/Users/mayoff/t/hotseat2/hotseat2/main.m:17
Notice frame #11. It's a call to _dispatch_main_queue_callback_4CF. That is the function that runs blocks put on the main queue. So viewDidAppear: was actually called from inside a block that was added to the main queue with dispatch_async.
The main queue is a serial queue. The definition of a serial queue is a queue that only executes one block at a time. If the queue is executing a block, no other block on that queue can start. So when you run the main run loop recursively, the run loop sees that it's already inside a block running on the main queue and doesn't try to start more blocks. That's why your semaphore-signaling block never runs and your app hangs.
Note that sometimes viewDidAppear: is called from inside a queued block, and sometimes it's not. You shouldn't rely on either behavior.

KVO/KVC crash on reloading previously unloaded bundles

I'm running into an issue with loadable bundles and KVO. It seems that any class that has KVO observers attached to an instance of it cannot be safely be unloaded via NSBundle's -unload method.
I'm doing the following:
for (int i = 0; i < 100; i++)
{
[bundle load];
Class bundleClass = [bundle principalClass];
[[[bundleClass alloc] init] release];
[bundle unload];
}
And in the bundle's principle class -init method,
[self addObserver: self
forKeyPath: #"name"
options: 0
context: nil];
self.name = #"jim";
The loop gets through a number of iterations, sometimes crashing on the second time round, sometimes on the thirtieth.
It always crashes with this backtrace, with the EXC_BAD_ACCESS signal.
#0 0x00007fff8a30deab in objc_msgSend ()
#1 0x00007fff8609d862 in NSKeyValueNotifyObserver ()
#2 0x00007fff860be99b in NSKeyValueDidChange ()
#3 0x00007fff8606b0fb in -[NSObject(NSKeyValueObserverNotification) didChangeValueForKey:] ()
#4 0x00000001007a4c2c in -[Bundle init] (self=0x101902130, _cmd=0x7fff8ea369b0) at /Users/joerick/Desktop/bundleTest/testbundle/Bundle.m:26
#5 0x0000000100001731 in -[SIAppDelegate applicationDidFinishLaunching:] (self=0x100326a90, _cmd=0x7fff876e285f, aNotification=0x100131ea0) at /Users/joerick/Desktop/bundleTest/bundleTest/SIAppDelegate.m:28
#6 0x00007fff8606ade2 in __-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_1 ()
#7 0x00007fff8b470e0a in _CFXNotificationPost ()
#8 0x00007fff86057097 in -[NSNotificationCenter postNotificationName:object:userInfo:] ()
#9 0x00007fff8e1bbaa7 in -[NSApplication _postDidFinishNotification] ()
#10 0x00007fff8e1bb80d in -[NSApplication _sendFinishLaunchingNotification] ()
....
Full code here
You can download a sample project showing this issue here.
I'm thinking that this is a bug in Cocoa, but I wonder if anybody could see if I'm doing anything stupid here?
I've reported this to Apple.
rdar://11017946

View interpretKeyEvents: but pass unwanted ones up the responder chain?

I'd really like my custom view to work with -moveLeft:, -deleteForward:, -selectAll:, etc., but I'd also like to pass any keys I didn't care about onward up the responder chain. Right now I'm overriding -keyDown: to call [self interpretKeyEvents:[NSArray arrayWithObject:event]];, but this seems to hog all the key events, even ones my view doesn't respond to.
Is there any way to pass unwanted events up the chain, but still respond to -moveLeft:, etc.? Or do I need to implement all my own actions in -keyDown: so that I know what I did and did not respond to?
Came across this trying to find a solution to this same problem. Never found anything online, but I came up with something that seems to work well so far. Here's what I'm doing:
Subclass your NSTextView (or whatever you're using) and create an instance variable to temporarily store the key down event . . .
#interface MyTextView : NSTextView {
NSEvent* _keyDownEvent;
}
#end
Then define your view's methods like so (take out the retain/release junk if you're using automatic reference counting):
#implementation MyTextView
- (id)initWithFrame:(NSRect)frame {
if (self = [super initWithFrame:frame]) {
_keyDownEvent = nil;
}
return self;
}
- (void)keyDown:(NSEvent*)event {
[_keyDownEvent release];
_keyDownEvent = [event retain];
[super keyDown:event];
}
- (void)doCommandBySelector:(SEL)selector {
if (_keyDownEvent && selector == #selector(noop:)) {
if ([self nextResponder]) {
[[self nextResponder] keyDown:[_keyDownEvent autorelease]];
} else {
[_keyDownEvent release];
}
_keyDownEvent = nil;
} else {
[super doCommandBySelector:selector];
}
}
- (void)dealloc {
[_keyDownEvent release];
[super dealloc];
}
#end
Here's how I arrived at this. When a key press isn't handled, you hear a beeping tone. So, I set a breakpoint on NSBeep(), and when the program broke, I spit out a stack trace in GDB:
#0 0x00007fff96eb1c2d in NSBeep ()
#1 0x00007fff96e6d739 in -[NSResponder doCommandBySelector:] ()
#2 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#3 0x00007fff96fda826 in -[NSWindow doCommandBySelector:] ()
#4 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#5 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#6 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#7 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#8 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#9 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#10 0x00007fff96e6d72b in -[NSResponder doCommandBySelector:] ()
#11 0x00007fff96f486ce in -[NSTextView doCommandBySelector:] ()
#12 0x00007fff96da1c93 in -[NSKeyBindingManager(NSKeyBindingManager_MultiClients) interpretEventAsCommand:forClient:] ()
#13 0x00007fff970f5382 in -[NSTextInputContext handleEvent:] ()
#14 0x00007fff96fbfd2a in -[NSView interpretKeyEvents:] ()
#15 0x00007fff96f38a25 in -[NSTextView keyDown:] ()
#16 0x0000000100012889 in -[MyTextView keyDown:] (self=0x1004763a0, _cmd=0x7fff972b0234, event=0x100197320) at /path/MyTextView.m:24
#17 0x00007fff96a16b44 in -[NSWindow sendEvent:] ()
#18 0x00007fff969af16d in -[NSApplication sendEvent:] ()
#19 0x00007fff969451f2 in -[NSApplication run] ()
#20 0x00007fff96bc3b88 in NSApplicationMain ()
#21 0x00000001000015e2 in main (argc=3, argv=0x7fff5fbff8f0) at /path/main.m:12
What's happening is this: When the key down event isn't used for text input, a "noop" command is sent up the response chain. By default this triggers a beep when it falls off the response chain. In my solution, the NSTextView subclass catches the noop command and instead throws the original keyDown event down the response chain. Then your NSWindow or other views will get any unused keyDown events as normal.
This is my swift implementation of #daxnitro's answer, and seems to work:
import Cocoa
class EditorTextView: NSTextView {
private var keyDownEvent: NSEvent?
required init?(coder aCoder: NSCoder) {
super.init(coder: aCoder)
}
override init() {
super.init()
}
override init(frame frameRect: NSRect, textContainer aTextContainer: NSTextContainer!) {
super.init(frame: frameRect, textContainer: aTextContainer)
}
override func keyDown(event: NSEvent) {
keyDownEvent = event
super.keyDown(event)
}
override func doCommandBySelector(aSelector: Selector) {
if aSelector != NSSelectorFromString("noop:") {
super.doCommandBySelector(aSelector)
} else if keyDownEvent != nil {
self.nextResponder?.keyDown(keyDownEvent!)
}
keyDownEvent = nil
}
}
I had a closely related issue with a custom NSTextView in an NSTableView. I wanted to be able to shift-select text in the NSTextView, but when all the text was selected, pass the shift-select up the responder chain to the NSTableView.
My solution was simply to override responds(to:) on my NSTextView and decide whether I wanted to handle it there.
override func responds(to aSelector: Selector!) -> Bool {
if aSelector == #selector(moveUpAndModifySelection(_:)) {
return selectedRange().location != 0
}
return super.responds(to: aSelector)
}

IOS4.2 app quits with EXC_BAD_ACCESS

An iPad app that runs fine under IOS3 fails under IOS4.2 It has a class that runs an http session from an operation queue and the failure is linked to this activity. Here is the console output:
Program received signal: “EXC_BAD_ACCESS”.
[Switching to thread 11523]
Running NSZombies enabled didn't reveal anything so I have been putting NSLog statements in the code and found that the crash occurs when a local variable is changed. Here is the code section:
self.currentOperation = [[[DeduceAccessOperation alloc] init] autorelease];
[self.currentOperation addObserver:self forKeyPath:#"isFinished"
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
context:NULL];
NSLog (#"Start observer added");
[operationQueue addOperation:self.currentOperation];
NSLog (#"Start operation added");
NSLog(#"State is %d", self.status);
self.status = IEnablerServiceUpdating;
NSLog (#"State updated");
And here is the console log output:
2010-12-08 21:26:44.548 UCiEnabler[5180:307] Start observer added
2010-12-08 21:26:44.550 UCiEnabler[5180:307] Start operation added
2010-12-08 21:26:44.552 UCiEnabler[5180:307] State is 1
Program received signal: “EXC_BAD_ACCESS”.
[Switching to thread 11523]
It is like status has become read-only (It's property is declared as atomic and readwrite).
The other relevant piece of information is that a sub-view has just been changed and it triggers the call on the above routine. It's code is:
//Start the update
UCiEnablerAppDelegate *controller = (UCiEnablerAppDelegate *)[[UIApplication sharedApplication] delegate];
[controller deduceIEnablerServiceAccess];
controller.serviceBusy = TRUE; //1.04
Has anyone seen anything like this?
Has anyone ideas where to look next?
Regards
Robin
Here's the stack trace:
#0 0x34a80464 in objc_msgSend
#1 0x3119543e in NSKVOPendingNotificationCreate
#2 0x3119535a in NSKeyValuePushPendingNotificationPerThread
#3 0x3117009a in NSKeyValueWillChange
#4 0x311682c6 in -[NSObject(NSKeyValueObserverNotification) willChangeValueForKey:]
#5 0x311cc718 in _NSSetIntValueAndNotify
#6 0x000097ce in -[IEnablerService startDeducingAccessState] at IEnablerService.m:55
#7 0x00002bc0 in -[UCiEnablerAppDelegate deduceIEnablerServiceAccess] at UCiEnablerAppDelegate.m:100
#8 0x0000a33e in -[RootViewControlleriPad animationDidStop:finished:context:] at RootViewController-iPad.m:43
#9 0x341bb336 in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:]
NSOperationQueue in iOS 4.2 now uses GrandCentralDispatch when starting NSOperations. There's a Technical Q&A here
Pretty much the queue now calls the NSOperation subclass's start method in a new thread regardless of the isConcurrent property. In my experience it means that if you are using NSURLConnection inside a start method your code will no longer run because the thread start is running on doesn't have an NSRunLoop.
Apple says that this change doesn't break compatibility because you were supposed to spawn a new thread in the start method anyway.
For backwards compatibility you should change your subclass from using start to using run.

EXC_BAD_ACCESS in an NSArray created 3 lines before crash

I'm just starting out on my first 'real' cocoa app. Note that this is Mac, not iPhone.
This function is called when my async download of onemanga finishes, and is intended to parse an NSArray list of manga from it. I get a NSArray from nodesForXPath, and retain it to make sure it's mine. (Also tried retaining it twice, heh). Unfortunately, trying to retrieve the count of the NSArray causes an EXC_BAD_ACCESS. The point of crashing is marked by two comments below.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(#"Download Succeeded! Received %d bytes of data. Beginning Parse.",[mangaListData length]);
NSString* theQuery = [[NSString alloc]initWithString:#"//tr/td[#class=\"ch-subject\"]/text()"];
NSError *XMLError=nil;
NSError *XPathError=nil;
NSString* mangaListHTML;
NSString* fixedMangaListHTML;
mangaListHTML = [[NSString alloc] initWithData:mangaListData encoding:NSUTF8StringEncoding];
fixedMangaListHTML = [mangaListHTML stringByReplacingOccurrencesOfString:#" & " withString:#" & "];
NSXMLDocument* xmlDoc = [[NSXMLDocument alloc] initWithXMLString:fixedMangaListHTML
options:(NSXMLNodePreserveWhitespace|NSXMLNodePreserveCDATA)
error:&XMLError];
if (XMLError) {
NSLog(#"XML Parse error: %#", XMLError);
return;
};
[fixedMangaListHTML release];
[mangaListHTML release];
NSArray* results = [[xmlDoc nodesForXPath:theQuery error:&XPathError] retain];
if (XMLError) {
NSLog(#"Parse error: %#", XPathError);
return;
};
NSLog(#"Parsing complete. Manga List = ");
//CRASH HAPPENS HERE
NSLog(#"Size of array: %#", [results count]);
//CRASH HAPPENS ABOVE
for(NSXMLNode* title in results){
NSLog(#"%#\n", title.description);
};
[XMLError release];
[XPathError release];
[connection release];
[mangaListData release];
}
Heres the output of where in gdb. (I don't really know how to use gdb yet, so any commands I could run to get more info here would be highly appreciated.)
#0 0x00007fff855691d1 in objc_msgSend_vtable5 ()
#1 0x00007fff87e97207 in _NSDescriptionWithLocaleFunc ()
#2 0x00007fff8509ba2d in _CFStringAppendFormatAndArgumentsAux ()
#3 0x00007fff8509aead in _CFStringCreateWithFormatAndArgumentsAux ()
#4 0x00007fff85119f5f in _CFLogvEx ()
#5 0x00007fff87ef937f in NSLogv ()
#6 0x00007fff87ef9317 in NSLog ()
#7 0x0000000100002bca in -[TMMoneManga connectionDidFinishLoading:] (self=0x1001999f0, _cmd=0x7fff8803b5de, connection=0x1001689a0) at /Users/ripdog/Documents/TheMangaMachine/TMMoneManga.m:120
#8 0x00007fff87f16b8c in _NSURLConnectionDidFinishLoading ()
#9 0x00007fff8063f18e in URLConnectionClient::_clientDidFinishLoading ()
#10 0x00007fff806a4502 in URLConnectionClient::ClientConnectionEventQueue::processAllEventsAndConsumePayload ()
#11 0x00007fff8062b8fb in URLConnectionClient::processEvents ()
#12 0x00007fff8062b6d8 in MultiplexerSource::perform ()
#13 0x00007fff850b6f21 in __CFRunLoopDoSources0 ()
#14 0x00007fff850b5119 in __CFRunLoopRun ()
#15 0x00007fff850b48df in CFRunLoopRunSpecific ()
#16 0x00007fff80b83ada in RunCurrentEventLoopInMode ()
#17 0x00007fff80b838df in ReceiveNextEventCommon ()
#18 0x00007fff80b83798 in BlockUntilNextEventMatchingListInMode ()
#19 0x00007fff8845fa2a in _DPSNextEvent ()
#20 0x00007fff8845f379 in -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] ()
#21 0x00007fff8842505b in -[NSApplication run] ()
#22 0x00007fff8841dd7c in NSApplicationMain ()
#23 0x00000001000017cd in main (argc=1, argv=0x7fff5fbff6c0) at /Users/ripdog/Documents/TheMangaMachine/main.m:13
Thanks a lot in advance.
The problem is with your format string. The %# specifier will display an Objective-C object, but [result count] is an integer. The correct format specifier for an integer is %d.
For reference, here is a complete list of Objective-C string format specifiers.
Your question indicated that the crash happens when you try to retrieve [result count]. However if you look at the call stack, your code is frame #7, and the next function on the stack (frame #6) is NSLog. So this tells you the problem is probably something to do with the call to NSLog, and not [result count]. [result count] will already have returned before control flow enters NSLog.
There are various techniques for debugging with gdb. Since you are debugging a crash, your focus will mostly be on examining the call stack, variables and memory (as opposed to stepping through your code as it executes.) So for this kind of debugging, these commands are essential:
up This moves the "focus" of the debugger up one frame of the call stack. Let's say you want to examine the variables in your program. You can't see them in objc_msgSend_vtable5 which is where the debugger is stopped. So use up 7 to jump up seven frames so you're looking at your code.
down Is the opposite of up. Oftentimes you want to look at what led to disaster, so jumping up to your code and then going down, down, down is a way to get an understanding of how disaster unfolded. (This isn't moving you forward and backward in time, of course.)
where Shows you part of the call stack. You already discovered this. My only tip is that you often only care about what's on the top of the call stack. You can use where n to print the first n frames of the call stack.
list Shows you the source code of the "focussed" frame, with an arrow indicating the execution point. So, for example, up 7 followed by list should show you the source of connectionDidFinishLoading with an indicator next to the call to NSLog. Using list is often more convenient than finding the code in XCode, if you just need to see a few lines of the surrounding context.
print Evaluates an expression and prints it. For example, you could do print [results count] to see what [results count] evaluates to. When the debugger is stopped with your program is in a bad state, print can act funny (it can really run code.) So often simple expressions work better.
info Info can tell you lots of things, but info locals is really valuable. It shows you the local variables that are in scope in the "focussed" frame of the debugger.
count returns an integer, not an object. Print it with %d not %#.
(If you do the latter, you implicitly convert the integer to a pointer to a non-existent object in the wilds of who knows where, and then invoke its description method.)