IOS 6 MKMapView crashes on [EAGLContext setCurrentContext] - opengl-es

We are developing an iPad application starting from map view with annotations.
By using storyboard when We switch to another view which has an opengl based charting solution (shinobi).
On return to the view with map it has no problem until a touch on the map to move it.
As we try to move map it crashes with exc_bad_access exception at [EAGLContext setCurrentContext]
Any ideas?
Here is the part of the crash log:
OS Version: iOS 6.0 (10A403)
Report Version: 104
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000c
Crashed Thread: 0
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 OpenGLES 0x39974b12 +[EAGLContext setCurrentContext:] + 74
1 VectorKit 0x32c64f0c -[VGLGPU setPaused:] + 120
2 VectorKit 0x32c54db8 -[VKMainLoop updateLinkState] + 492
3 VectorKit 0x32c54950 -[VKScreenCanvas _updateDisplayStatus:] + 104
4 VectorKit 0x32ccea9a -[VKScreenCanvas setGesturing:] + 254
5 MapKit 0x34defc3c -[MKMapView _willStartUserInteraction] + 48
6 MapKit 0x34de891a -[MKMapGestureController beginGesturing] + 50
7 MapKit 0x34de8c6c -[MKMapGestureController handlePan:] + 252
8 UIKit 0x379ead2c _UIGestureRecognizerSendActions + 124
9 UIKit 0x379b23d8 -[UIGestureRecognizer _updateGestureWithEvent:] + 388
10 UIKit 0x37b9f474 ...

I work for Shinobi and we've been investigating this - it's partly due to Apple's map code keeping hold of our GL-Context. As a temporary workaround, you can create a subclass of a ShinobiChart and nil-out the GL context in the chart's dealloc method, like so:
- (void) dealloc {
[super dealloc];
[EAGLContext setCurrentContext:nil]; // must be after dealloc
}
or if you're using ARC, (since sending dealloc is not allowed):
#import <ShinobiCharts/SChartCanvas.h>
#interface ShinobiChartGl : ShinobiChart
#end
#implementation ShinobiChartGl
- (void) dealloc
{
[self.canvas.glView removeFromSuperview];
self.canvas.glView = nil; // force glView dealloc
[EAGLContext setCurrentContext:nil];
}
#end
Hope this helps, but do contact us directly - we'll have a full fix out in our next release.

for those who did not work even tried [EAGLContext setCurrentContext:nil]; on dealloc, try this
dispatch_async(dispatch_get_main_queue(), ^{
[EAGLContext setCurrentContext:nil];
});
EAGLContext should be set on main thread.

Related

Why is NSFontManager.availableMembers(ofFontFamily:) crashing in Xcode 8 GM?

I wrote this in Xcode 8 Beta 6 (8S201h):
guard let faceMembers = NSFontManager.shared().availableMembers(ofFontFamily: familyName ?? fontName) else { return nil }
And it worked just fine. Now that I've upgraded to Xcode 8 GM Seed (8A218a) Xcode 8 (8A218a), it crashes (EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)).
Using the debugger to narrow it down, I found that something in NSFontManager.availableMembers(ofFontFamily:) really hates this, since it crashes no matter what I put in there, even with common (definitely installed!) fonts like Helvetica Neue.
(lldb) po NSFontManager.shared()
<NSFontManager: 0x6100000a24c0>
(lldb) po familyName
▿ Optional<String>
- some : "Helvetica Neue"
(lldb) po fontName
"HelveticaNeue"
(lldb) po NSFontManager.shared().availableMembers(ofFontFamily: familyName ?? fontName)
error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
The process has been returned to the state before expression evaluation.
(lldb) po NSFontManager.shared().availableMembers(ofFontFamily: familyName!)
error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
The process has been returned to the state before expression evaluation.
(lldb) po NSFontManager.shared().availableMembers(ofFontFamily: "Not a real font?!")
nil
So when I pass it a valid font family name, it crashes... but when I pass it a fake one, it returns nil.
Is this a problem I can solve, or just an issue with Xcode 8 GM Seed Xcode 8 which will be solved in an SDK update?
After looking through the crash log, I saw this suspiciousness:
Thread 0 Crashed:: Dispatch queue: com.apple.main-thread
0 libswiftFoundation.dylib 0x0000000107cbb249 _TZFE10FoundationSa26_forceBridgeFromObjectiveCfTCSo7NSArray6resultRGSqGSax___T_ + 153
1 libswiftCore.dylib 0x00000001079031f3 swift_dynamicCast + 1635
2 libswiftCore.dylib 0x000000010790448b _dynamicCastFromExistential(swift::OpaqueValue*, swift::OpaqueValue*, swift::TargetExistentialTypeMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*, swift::DynamicCastFlags) + 91
3 libswiftCore.dylib 0x0000000107903919 swift_dynamicCast + 3465
4 libswiftFoundation.dylib 0x0000000107d6a348 _TPA__TFFs15_arrayForceCastu0_rFGSax_GSaq__U_FQ_Q0_ + 56
5 libswiftFoundation.dylib 0x0000000107cbbc45 _TFEsPs10Collection3mapurfzFzWx8Iterator7Element_qd__GSaqd___ + 885
6 libswiftFoundation.dylib 0x0000000107cbb4c3 _TFs15_arrayForceCastu0_rFGSax_GSaq__ + 227
7 libswiftFoundation.dylib 0x0000000107cbb7a5 _TZFE10FoundationSa36_unconditionallyBridgeFromObjectiveCfGSqCSo7NSArray_GSax_ + 197
So it seems like it's crashing within Swift-Foundation, in some function called _forceBridgeFromObjectiveC... not sure if that helps anyone but it does confirm it's within the SDK/runtime.
The only way that I could figure out how to work around this in the meantime was to create a static method in an objective-c class. I then imported the header into my bridging header and called the static method from Swift 3, where it worked fine.
Hope this helps you get through these difficult times!
#import <Foundation/Foundation.h>
#import <Cocoa/Cocoa.h>
#interface WorkAround : NSObject
+ (NSArray *)typefacesForFontFamily:(NSString *)family;
#end
#import "WorkAround.h"
#implementation WorkAround
/// Returns an array of arrays, or nil, that contain information about
/// each typeface found for the specified font family.
+ (NSArray *)typefacesForFontFamily:(nonnull NSString *)family {
NSFontManager *fontManager = [NSFontManager sharedFontManager];
return [fontManager availableMembersOfFontFamily:family];
}
#end
Joseph E.'s answer is a good starting point. However to get it to work in Swift 3, Xcode 8 (8A218a) I had to approach differently...
Subclass NSFontManager (in Objective C), and create the bridging header if you don't already have one.
Make sure to change the language to (Objective C). Its important that you do it this way, as it appears you cannot directly create an objective c m files?, even though there is an option to do so.
Implementation
FontManager.h
#import <Cocoa/Cocoa.h>
#interface FontManager : NSFontManager
NS_ASSUME_NONNULL_BEGIN
+ (NSArray *)typefacesForFontFamily:(NSString *)family;
NS_ASSUME_NONNULL_END
#end
FontManager.m
#import "FontManager.h"
#implementation FontManager
NS_ASSUME_NONNULL_BEGIN
+ (NSArray *)typefacesForFontFamily:(nonnull NSString *)family {
NSFontManager *fontManager = [self sharedFontManager];
return [fontManager availableMembersOfFontFamily:family];
}
NS_ASSUME_NONNULL_END
#end
bridging-header.h
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "FontManager.h"
Usage in your Swift 3 project
if let fontMembers = FontManager.typefaces(forFontFamily: "Arial") as? [[Any]] { }

UIImage: imageNamed crash

I am having truble while using [UIImage imageNamed:] method
It appeares that crash occured when launching app from killed state and getting an resource image.
All my images are stored in bundle and no issue with background thread.
Following is crash log
Thread : Crashed: com.apple.main-thread
19 UIKit 0x186739714 +[UIImage imageNamed:inBundle:compatibleWithTraitCollection:] + 380
20 UIKit 0x18658cc8c +[UIImage imageNamed:] + 124
This happens on
UIImage * image = [UIImage imageNamed:#"abc.png"];

PDFDocument removePageAtIndex: is not working when updated to Mac OS X 10.11

I am using the PDFKit Framework into my cocoa app for PDFViewer.When I am trying to delete one of the page from the PDFDocument The app freezes at the line of code
[[self pdfDocument] removePageAtIndex:0]; // can see this Problem only in Mac OS X 10.11
This works perfectly when I run the app in Mac OS X 10.10
I read all the related apple documents but I didn't get any solution yet.
Here is the backtrace :
* thread #1: tid = 0x85e1, 0x00007fff92571f5e libsystem_kernel.dylib`__psynch_cvwait + 10, queue = 'com.apple.main-thread', stop reason = signal SIGTERM
frame #0: 0x00007fff92571f5e libsystem_kernel.dylib`__psynch_cvwait + 10
frame #1: 0x00000001006c05f7 libsystem_pthread.dylib`_pthread_cond_wait + 767
frame #2: 0x00007fff904c6e32 Foundation`-[__NSOperationInternal _waitUntilFinished:] + 131
frame #3: 0x00007fff904921fa Foundation`-[NSOperationQueue waitUntilAllOperationsAreFinished] + 254
* frame #4: 0x000000010017efe1 Neat`-[NRMPDFCoordinator waitUntilAllOperationsAreFinished](self=0x0000608000ad3be0, _cmd=0x00007fff8877e285) + 145 at NRMPDFCoordinator.m:1362
frame #5: 0x00000001000109cf Neat`-[NRMItemEditorDocument saveDocumentWithDelegate:didSaveSelector:contextInfo:](self=0x000060000094a190, _cmd=0x00007fff88777581, delegate=0x0000000000000000, didSaveSelector=0x0000000000000000, contextInfo=0x0000000000000000) + 1151 at NRMItemEditorDocument.m:325
frame #6: 0x000000010001018a Neat`-[NRMItemEditorDocument saveDocument:](self=0x000060000094a190, _cmd=0x00007fff8874cbb4, sender=0x00006080003a8b20) + 58 at NRMItemEditorDocument.m:234
frame #7: 0x0000000100013bef Neat`-[NRMItemEditorWindowController saveAndClose:](self=0x00006080003a8b20, _cmd=0x00000001002cf2d2, sender=0x000060000094a5b0) + 95 at NRMItemEditorWindowController.m:244
frame #8: 0x00007fff87068082 libsystem_trace.dylib`_os_activity_initiate + 75
frame #9: 0x00007fff87fc79b5 AppKit`-[NSApplication sendAction:to:from:] + 460
frame #10: 0x00007fff87fd9bb2 AppKit`-[NSControl sendAction:to:] + 86
frame #11: 0x00007fff87fd9adc AppKit`__26-[NSCell _sendActionFrom:]_block_invoke + 131
frame #12: 0x00007fff87068082 libsystem_trace.dylib`_os_activity_initiate + 75
frame #13: 0x00007fff87fd9a39 AppKit`-[NSCell _sendActionFrom:] + 144
frame #14: 0x00007fff87068082 libsystem_trace.dylib`_os_activity_initiate + 75
frame #15: 0x00007fff87fd805e AppKit`-[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 2693
frame #16: 0x00007fff88020d1c AppKit`-[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 744
frame #17: 0x00007fff87fd6788 AppKit`-[NSControl mouseDown:] + 669
frame #18: 0x00007fff88524575 AppKit`-[NSWindow _handleMouseDownEvent:isDelayedEvent:] + 6322
frame #19: 0x00007fff88525559 AppKit`-[NSWindow _reallySendEvent:isDelayedEvent:] + 212
frame #20: 0x00007fff87f6ad31 AppKit`-[NSWindow sendEvent:] + 517
frame #21: 0x00007fff87eeaccb AppKit`-[NSApplication sendEvent:] + 2540
frame #22: 0x0000000100225f35 Neat`-[NRMApplication sendEvent:](self=0x00006000001205a0, _cmd=0x00007fff88749e04, event=0x0000608000725640) + 1141 at NRMApplication.m:95
frame #23: 0x00007fff87d51f3e AppKit`-[NSApplication run] + 796
frame #24: 0x00007fff87d1b162 AppKit`NSApplicationMain + 1176
frame #25: 0x0000000100012d67 Neat`main(argc=3, argv=0x00007fff5fbff718) + 119 at main.m:21
frame #26: 0x0000000100001e74 Neat`start + 52
here is the method where I am using removePageAtIndex method of PDFDocument
-(NSError *)removePageOpImpl:(NRMPDFOperation *)op
{
NSLog(#"\n Inside removePageOpImpl Method ...");
NSError* error = [self loadDocument];
if( !error )
{
NSUInteger index = [self pageIndexForId:[op pageId]];
NSLog(#"Page count: %ld", [self pageCount]);
if( index < [self pageCount] )
{
NSLog(#"PDF Document:-- %#", [self pdfDocument]);
NSLog(#"Index is: %ld", index);
#try {
[(PDFDocument *)[self pdfDocument] removePageAtIndex:index];//At this line the app getting freezed and control is ended.
NSLog(#"Page count after delete: %ld", [self pageCount]);
}
#catch (NSException *exception) {
NSLog(#"Exception: %#", exception);
}
#finally {
NSLog(#"Finally called");
[[self mutablePageIdList] removeObjectAtIndex:index];
[self updatePageLabelsFromIndex:index];
[self updateChangeCount:NSChangeDone];
self.contentsChanged = YES;
}
}
else
{
// TODO: error
}
}
return error;
}
Can anyone please suggest me what might be the problem... also attached screenshots of the Queues which were blocking the UI
I tried applying dispatch_async on main queue to the PDFDocument page removal operations like below
- (NSError *)removePageOpImpl:(NRMPDFOperation *)op
{
NSError* error = [self loadDocument];
if( !error )
{
NSUInteger index = [self pageIndexForId:[op pageId]];
if( index < [self pageCount] )
{
dispatch_async(dispatch_get_main_queue(), ^{
[[self pdfDocument] removePageAtIndex:index];
[[self mutablePageIdList] removeObjectAtIndex:index];
[self updatePageLabelsFromIndex:index];
[self updateChangeCount:NSChangeDone];
self.contentsChanged = YES;
});
}
else
{
// TODO: error
}
}
return error;
}
Now the app is not hanging, but I fall into another problem. I have other operations which should run synchronously after the removePageOpImpl operations. but they are executing before removePageOpImpl completion which is changing the behaviour of my app. Can you suggest me how can I execute other operations synchronously after removePageOpImpl. I read about completion handler but, in this scenario I am confused of how to use it.
Please suggest
You have created a nice little deadlock here.
Your main thread is waiting for an operation to finish, but that operation (indicated by this trace)...
is running on a background thread and, as you can see, it's waiting on a semaphore that is most likely only going to be signaled from the main thread. This has the earmarks of something like dispatch_sync to the main thread. Since it happens inside the PDFDocument implementation, I imagine it is trying to make sure it runs something on the main thread before returning to the user (reader/writer lock
Thus, your main thread is waiting for an operation to finish, and that operation is waiting for the main thread to finish what it's trying to do. Classic deadlock.
This happens because the main thread kicks off the save, and then waits for everything to complete before progressing (but some of that other work also needs to run on the main thread).
You need to kick off the save as an asynchronous operation, so it is not running on the main thread while waiting for the operations to complete. Then, when the save is done, if you have to update UI, it can report its success/failure via a completion block or delegate running on the main thread.

Continuously write content of a log file into an NSTextview

I'm having trouble with an NSTextview which should continously update with the contents of a log file. The app is a master-detail UI, the master view contains an array of "backup" objects, while the detail view contains an NSTabView with one of the tabs containing the NSTextview.
Basically I want something like a tail -f logfile putting it's output into the NSTextview. Instead of using NSTask etc., I went for binding the NSTextview's "Attributed String" to a property of my "backup" object (so I can set the font):
backup.m
- (NSAttributedString *)logContent
{
NSDictionary *attributes = #{NSFontAttributeName:[NSFont fontWithName:#"Monaco" size:12]};
NSString *str = [NSString stringWithContentsOfURL:theLogfile encoding:NSUTF8StringEncoding error:nil];
if (str) {
NSAttributedString *attrstr = [[NSAttributedString alloc] initWithString:str attributes:attributes];
return attrstr;
} else
return nil;
}
Then I hook an FSEventStream to the logfile which informs a callback everytime the logfile changes. Inside the callback, I manually inform listeners that the property has changed and scroll down the NSTextview:
backup.m
- (void)_fsEventsCallback:(NSArray *)eventPaths{
if ([eventPaths containsObject:theLogfile.path]){
[self willChangeValueForKey:#"logContent"];
[self didChangeValueForKey:#"logContent"];
[_myAppDel.logTextView scrollRangeToVisible:NSMakeRange([[_myAppDel.logTextView string] length], 0)];
}}
The actual remove is done via an NSNotification:
App Delegate.m
- (void)removeBackupObject:(NSNotification *)notification
{
if (notification.object) {
[self.backupsArrayController removeObject:notification.object];
}
}
This works and I like the code better than using an NSTask, but the app occasionally crashes with a strange error when I tell the NSArrayController to remove a "backup" object:
Crashed Thread: 5 Dispatch queue: com.apple.root.low-priority
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Application Specific Information:
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSSetM: 0x60000045f1a0> was mutated while being enumerated.'
terminating with uncaught exception of type NSException
abort() called
Application Specific Backtrace 1:
0 CoreFoundation 0x00007fff8aec425c __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff8a7a4e75 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8aec3b64 __NSFastEnumerationMutationHandler + 164
3 Foundation 0x00007fff8d0e3f05 -[NSISEngine chooseOutgoingRowHeadForIncomingRowHead:] + 305
4 Foundation 0x00007fff8d0e1aa8 -[NSISEngine minimizeConstantInObjectiveRowWithHead:] + 114
5 Foundation 0x00007fff8d0e1623 -[NSISEngine optimize] + 147
6 Foundation 0x00007fff8d0e851d -[NSISEngine constraintDidChangeSuchThatMarker:shouldBeReplacedByMarkerPlusDelta:] + 296
7 Foundation 0x00007fff8d0e839e -[NSISEngine tryToChangeConstraintSuchThatMarker:isReplacedByMarkerPlusDelta:undoHandler:] + 420
8 Foundation 0x00007fff8d0d3798 -[NSLayoutConstraint _tryToChangeContainerGeometryWithUndoHandler:] + 462
9 Foundation 0x00007fff8d0d31b3 -[NSLayoutConstraint _setSymbolicConstant:constant:] + 402
10 AppKit 0x00007fff8e2ac4ba -[NSView(NSConstraintBasedLayout) _autoresizingConstraints_frameDidChange] + 247
11 AppKit 0x00007fff8e2ab25f -[NSView setFrameOrigin:] + 901
12 AppKit 0x00007fff8e2b51b6 -[NSView setFrame:] + 259
13 AppKit 0x00007fff8e682c2f -[NSClipView _updateOverhangSubviewsIfNeeded] + 739
14 AppKit 0x00007fff8e2e80a1 -[NSClipView _scrollTo:animateScroll:flashScrollerKnobs:] + 1984
15 AppKit 0x00007fff8e2e76ff -[NSClipView _reflectDocumentViewFrameChange] + 128
16 AppKit 0x00007fff8e2ac0ac -[NSView _postFrameChangeNotification] + 203
17 AppKit 0x00007fff8e2b5852 -[NSView setFrameSize:] + 1586
18 AppKit 0x00007fff8e447bac -[NSTextView(NSPrivate) _setFrameSize:forceScroll:] + 764
19 AppKit 0x00007fff8e3b222f -[NSTextView setConstrainedFrameSize:] + 633
20 AppKit 0x00007fff8e443f70 -[NSLayoutManager(NSPrivate) _resizeTextViewForTextContainer:] + 1025
21 AppKit 0x00007fff8e35133e -[NSLayoutManager(NSPrivate) _recalculateUsageForTextContainerAtIndex:] + 2636
22 AppKit 0x00007fff8e343fb1 _enableTextViewResizing + 211
23 AppKit 0x00007fff8e34a6ef -[NSLayoutManager textStorage:edited:range:changeInLength:invalidatedRange:] + 557
24 AppKit 0x00007fff8e34a4aa -[NSTextStorage _notifyEdited:range:changeInLength:invalidatedRange:] + 149
25 AppKit 0x00007fff8e451a2c -[NSTextStorage processEditing] + 200
26 AppKit 0x00007fff8e44d832 -[NSTextStorage endEditing] + 110
27 Foundation 0x00007fff8d10b434 -[NSMutableAttributedString removeAttribute:range:] + 219
28 AppKit 0x00007fff8e4ca2c1 -[NSTextView setTextColor:] + 156
29 AppKit 0x00007fff8ea19baf -[_NSTextPlugin showValue:inObject:] + 128
30 AppKit 0x00007fff8e314797 -[NSValueBinder _adjustObject:mode:observedController:observedKeyPath:context:editableState:adjustState:] + 846
31 AppKit 0x00007fff8e3143aa -[NSValueBinder _observeValueForKeyPath:ofObject:context:] + 282
32 AppKit 0x00007fff8e314215 -[NSTextValueBinder _observeValueForKeyPath:ofObject:context:] + 43
33 Foundation 0x00007fff8d09af28 NSKeyValueNotifyObserver + 387
34 Foundation 0x00007fff8d0d7ed1 -[NSObject(NSKeyValueObservingPrivate) _notifyObserversForKeyPath:change:] + 1115
35 AppKit 0x00007fff8e306d88 -[NSController _notifyObserversForKeyPath:change:] + 209
36 AppKit 0x00007fff8e4385ff -[NSArrayController didChangeValuesForArrangedKeys:objectKeys:indexKeys:] + 125
37 AppKit 0x00007fff8e62179f -[NSArrayController _removeObjectsAtArrangedObjectIndexes:contentIndexes:objectHandler:] + 724
38 AppKit 0x00007fff8e621d1f -[NSArrayController _removeObjects:objectHandler:] + 502
Before I go into debugging what's going wrong, or implement the NSTask / tail -f approach, I'd like to know:
Are there are more elegant solutions to this problem?
This is an unsynchronized access issue. The notification is executing on one thread and the fsevent callback on another and both of them are accessing the ArrayController's underlying array and the textview at the same time.
Option 1 - Quick and dirty fix
Synchronize access accross threads. This done by acquiring a lock on the particular resource being accessed: the executing thread is gets the lock and all threads that attempt to acess that resource will be blocked until the locking thread releases the lock. More info can be found in the Threadding programming guide
Your code thus becomes:
- (void)_fsEventsCallback:(NSArray *)eventPaths{
if ([eventPaths containsObject:theLogfile.path])
#synchronized(self.logContent) {
[self willChangeValueForKey:#"logContent"];
[self didChangeValueForKey:#"logContent"];
}
#synchronized(_myAppDel.logTextView.string) {
[_myAppDel.logTextView scrollRangeToVisible:NSMakeRange([[_myAppDel.logTextView string] length], 0)];
}
}
}
- (void)removeBackupObject:(NSNotification *)notification
{
if (notification.object) {
#synchronized(self.backupsArrayController) {
[self.backupsArrayController removeObject:notification.object];
}
}
}
This will most likely solve your immediate problem, but however, IT IS A CHEAP AND DIRTY FIX and will effectively make your application's threads wait for each other every time.
Option 2 - The better way
Always update your ui on the main thread and do actual work on secondary threads.
The FSEvents callback is called on a secondary thread, the NSNotification that you are posting is responded to on another secondary thread and all of them operate on objects that are not really thread safe. Generally, NSMutable* objects are thread safe on access but not on mutations. In other words, if you're altering their contents, you'd better pay attention whos is doing what and when. :)
More info on which Cocoa Objects are thread safe and which are not can be found here in the Thread Safety section in the document I referred above. (That is quite a good piece of reading btw)
The idea is to tell the app to update the interface on the main thread, like so:
- (void)_fsEventsCallback:(NSArray *)eventPaths{
if ([eventPaths containsObject:theLogfile.path]){
[self willChangeValueForKey:#"logContent"];
[self didChangeValueForKey:#"logContent"];
[[NSApp delegate] performSelectorOnMainThread:#selector(scrollToWhereWeNeedTo) withObject:nil];
}}
AppDelegate.m
- (void)scrollToWhereWeNeedTo
{
[self.logTextView scrollRangeToVisible:NSMakeRange([[self.logTextView string] length], 0)];
}
- (void)removeBackupObject:(NSNotification *)notification
{
if (notification.object) {
[[NSApp delegate] performSelectorOnMainThread:#selector(removeObjectFromArrayController) withObject:notification.object];
}
}
- (void)removeObjectFromArrayController:(id)theObject
{
[self.backupsArrayController removeObject:theObject];
}
What you are effectively doing here is you are scheduling the scroll operation and the removing object operations on the main thread's runloop, thus eliminating any potential access conflict, because they will be in a queue, one after the other.
Also, please look at any other potential places in your app where access conflicts could happen.
I really hope this helps and does not confuse you even further. Cocoa can be a pain at first but hey, what doesn't kill you makes you stronger!
I solved the problem with the help of Cătălin Stan by executing the removeObject: call on the main thread like so:
- (void)removeBackupObject:(NSNotification *)notification
{
if (notification.object) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.backupsArrayController removeObject:notification.object];
});
}
}

Help with crash log

My app is crashing on Lion when it awakes from sleep.
The problem seems to be with a background thread that is looking for weather info.
I'm not sure but I think the crash log is telling me that the autorelease pool is popping objects that are no longer there, can someone help me confirm this?
Here is the relevant details for the Crash log:
Process: myApp [14187] Identifier: myApp Version:
??? (???) Code Type: X86-64 (Native) Parent Process: launchd
[224]
Date/Time: 2011-08-24 18:58:00.581 -0400 OS Version: Mac OS
X 10.7.1 (11B26) Report Version: 9
Crashed Thread: 7
Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes:
KERN_INVALID_ADDRESS at 0x0000000000000010
Application Specific Information: objc[14187]: garbage collection is
OFF
Thread 7 Crashed: 0 libobjc.A.dylib
0x00007fff9321700b (anonymous
namespace)::AutoreleasePoolPage::pop(void*) + 385 1
com.apple.CoreFoundation 0x00007fff961306a5
CFAutoreleasePoolPop + 37 2 com.apple.Foundation
0x00007fff969350d7 -[NSAutoreleasePool drain] + 154 3
com.piso13.opusDomini 0x00000001000acb91 -[Weather
internalStart] + 417 4 com.apple.Foundation
0x00007fff9698b1ea -[NSThread main] + 68 5 com.apple.Foundation
0x00007fff9698b162 NSThread_main + 1575 6 libsystem_c.dylib
0x00007fff90b068bf _pthread_start + 335 7 libsystem_c.dylib
0x00007fff90b09b75 thread_start + 13
Here is my code for Weather Internal Start:
-(void)internalStart{
pool = [[NSAutoreleasePool alloc] init];
forecast = FALSE;
liveweather = FALSE;
NSString *query = [self generateQuery];
if (query == nil) {
[pool drain];
return;
}
XmlWrapper * xmlWrapper = [[XmlWrapper alloc] initWithQuery:query delegate:self name:#"liveweather"];
[xmlWrapper release];
query = [self generateForecastQuery];
xmlWrapper = [[XmlWrapper alloc] initWithQuery:query delegate:self name:#"forecast"];
[xmlWrapper release];
[pool drain];
}
Should I even be calling [pool drain] ?
create your autorelease pools with bound lifetimes and explicit scopes.
in this case, you store your autorelease pool in an ivar (presumed).
just make it local to the method, like so:
- (void)internalStart
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
//...
[pool drain], pool = nil;
}
the problems that are typically introduced are:
1) autorelease pools are stack based (pools are pushed and popped). by holding onto it, you can easily mess up the stack order.
2) if this class operates in a multithreaded context, you can easily leak pools or destroy the stack order when you push and pop pools from multiple threads.
3) you could also leak pools in multithreaded contexts
Unfortunately, autoreleasepool crashes are some of the hardest to debug. Start with the static analyzer, which can find some things.
Then turn on NSZombies.
Your XmlWrapper object is a bit strange. Why do you immediately release it as soon as you create it? Is this a wrapper around NSURLConnection? You should still hold onto the object so that you can cancel it or clear its delegate when this object is released.
Make sure you're using accessors for all your ivars rather than accessing them directly. Direct access to ivars outside of init and dealloc is the #1 cause of these kinds of crashes in my experience.

Resources