Mind boggling QTMovie export crash - cocoa

Hey guys... I'm at my wits end here. I've been focusing on this issue for the last 3 days it seems, and I'm still no closer to solving it. I've got a queue of videos that I'm converting one after the other in a background thread. Most of the time it works as expected, but every so often, I get a weird crash, always at the same point. I can't for the life of me figure out why it's happening. I've got garbage collection enabled. Here is my conversion code.
Here is the stack trace.
Edit: After a bit more debugging, I am back to the conclusion that maybe it is garbage collector related. If I place the following line just before the line that converts the video, I get a drastic increase in the amount of these errors that I see...
[[NSGarbageCollector defaultCollector] collectExhaustively];
NSInvalidArgumentException
-[NSPathStore2 objectForKey:]: unrecognized selector sent to instance 0x1073570
(
0 CoreFoundation 0x92fc16ba __raiseError + 410
1 libobjc.A.dylib 0x901b4509 objc_exception_throw + 56
2 CoreFoundation 0x9300e90b -[NSObject(NSObject) doesNotRecognizeSelector:] + 187
3 CoreFoundation 0x92f67c36 ___forwarding___ + 950
4 CoreFoundation 0x92f67802 _CF_forwarding_prep_0 + 50
5 QTKit 0x903d3280 MovieProgressProc + 62
6 QuickTime 0x95a66062 convertFileProgress + 212
7 QuickTime3GPP 0x1e7bcaa2 Spit3GP2_Progress + 180
8 QuickTime3GPP 0x1e7c01d8 Spit3GP2_FromProceduresToDataRef + 3438
9 CarbonCore 0x90b0d054 _ZL38CallComponentFunctionCommonWithStoragePPcP19ComponentParametersPFlvEm + 54
10 QuickTime3GPP 0x1e7be33d Spit3GP2_ComponentDispatch + 129
11 CarbonCore 0x90b057c9 CallComponentDispatch + 29
12 QuickTime 0x95befb97 MovieExportFromProceduresToDataRef + 49
13 QuickTime3GPP 0x1e7bdf84 Spit3GP2_ToDataRef + 1987
14 CarbonCore 0x90b1865d callComponentStorage_4444444 + 63
15 CarbonCore 0x90b0d054 _ZL38CallComponentFunctionCommonWithStoragePPcP19ComponentParametersPFlvEm + 54
16 QuickTime3GPP 0x1e7be33d Spit3GP2_ComponentDispatch + 129
17 CarbonCore 0x90b057c9 CallComponentDispatch + 29
18 QuickTime 0x95befbe2 MovieExportToDataRef + 73
19 QuickTime 0x95a6e9bb ConvertMovieToDataRef_priv + 1690
20 QuickTime 0x95bdc591 ConvertMovieToDataRef + 71
21 QTKit 0x903e0954 -[QTMovie_QuickTime writeToDataReference:withAttributes:error:] + 2692
22 QTKit 0x903c5110 -[QTMovie_QuickTime writeToFile:withAttributes:error:] + 111
23 Mevee 0x0005871d -[ConversionQueue convertVideo:] + 509
24 Mevee 0x00058341 -[ConversionQueue startConvertingItems] + 145
25 Foundation 0x9520fbf0 -[NSThread main] + 45
26 Foundation 0x9520fba0 __NSThread__main__ + 1499
27 libSystem.B.dylib 0x9475a85d _pthread_start + 345
28 libSystem.B.dylib 0x9475a6e2 thread_start + 34
)
- (id) init
{
if(!(self = [super init])) return self;
convertingIndex = 0;
conversionPaths = [[NSMutableArray alloc] init];
[conversionPaths addObject:#"/Users/Morgan/Desktop/Convertable Media/Movies/2 Fast 2 Furious/2 Fast 2 Furious.mp4"];
[conversionPaths addObject:#"/Users/Morgan/Desktop/Convertable Media/Movies/101 Dalmations/101 Dalmations.mp4"];
[conversionPaths addObject:#"/Users/Morgan/Desktop/Convertable Media/Movies/300/300.mp4"];
[conversionPaths addObject:#"/Users/Morgan/Desktop/Convertable Media/Movies/1408/1408.mp4"];
[conversionPaths addObject:#"/Users/Morgan/Desktop/Convertable Media/Movies/A Few Good Men/A Few Good Men.mp4"];
[conversionPaths addObject:#"/Users/Morgan/Desktop/Convertable Media/Movies/A Goofy Movie/A Goofy Movie.mp4"];
[conversionPaths addObject:#"/Users/Morgan/Desktop/Convertable Media/Movies/A Single Man/A Single Man.mp4"];
[conversionPaths addObject:#"/Users/Morgan/Desktop/Convertable Media/Movies/A View to a Kill/A View to a Kill.mp4"];
[conversionPaths addObject:#"/Users/Morgan/Desktop/Convertable Media/Movies/Across the Universe/Across the Universe.mp4"];
backgroundThread = [[NSThread alloc] initWithTarget:self selector:#selector(startConvertingItems) object:nil];
[backgroundThread start];
return self;
}
- (void) startProcessingQueue
{
}
- (void) startConvertingItems
{
NSInteger iterations = 0;
while(iterations < 100)
{
NSString* nextPath = [conversionPaths objectAtIndex:convertingIndex];
NSLog(#"ITERATION %d", iterations);
[self convertVideo:nextPath];
convertingIndex += 1;
if(convertingIndex >= [conversionPaths count])
convertingIndex = 0;
iterations += 1;
}
}
- (void) openMovieOnMainThread:(NSString*)path
{
NSError* error = nil;
movie = [[QTMovie alloc] initWithFile:path error:&error];
if(movie == nil || error != nil || ![movie detachFromCurrentThread])
movie = nil;
}
- (void) closeMovieOnMainThread
{
//[movie attachToCurrentThread];
//[movie release];
}
- (BOOL) convertVideo: (NSString*)path
{
[self performSelectorOnMainThread:#selector(openMovieOnMainThread:) withObject:path waitUntilDone:YES];
if(movie == nil) {
NSLog(#"ERROR OPENING MOVIE");
return NO;
}
[QTMovie enterQTKitOnThreadDisablingThreadSafetyProtection];
[movie attachToCurrentThread];
[movie setDelegate:self];
NSString* tempItemPath = #"/Users/Morgan/Desktop/test.mp4";
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], QTMovieExport,
[NSNumber numberWithLong:'3gpp'], QTMovieExportType,
nil];
NSError* error = nil;
if(![movie writeToFile:tempItemPath withAttributes:attrs error:&error]) {
NSLog(#"ERROR CONVERTING MOVIE");
return NO;
}
[movie invalidate];
[movie detachFromCurrentThread];
[QTMovie exitQTKitOnThread];
[self performSelectorOnMainThread:#selector(closeMovieOnMainThread) withObject:nil waitUntilDone:YES];
return YES;
}
- (BOOL)movie:(QTMovie *)aMovie shouldContinueOperation:(NSString *)op withPhase:(QTMovieOperationPhase)phase atPercent:(NSNumber *)percent withAttributes:(NSDictionary *)attributes
{
switch (phase)
{
case QTMovieOperationBeginPhase:
NSLog(#"Conversion started");
break;
case QTMovieOperationUpdatePercentPhase:
NSLog(#"Conversion progress: %f", [percent floatValue]);
break;
case QTMovieOperationEndPhase:
NSLog(#"Conversion finished.");
break;
}
return YES;
}

Ahhh... I found out it was the stupid garbage collector. Reworked my app to work with reference counting rather than garbage collection, and smooth sailing. Has anyone else come across similar garbage collection bugs? I had a strong reference to a root object for my movie file, so I don't think that was the problem.

Related

Error when running my ios sumilator : Exception '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]

I have just done some configs in Xcode and appdelegate.m for RNFirebase, RNFBSDK, and google Sign-In. After following al the steps I have an error when running my ios simulator with react-native run ios.
I have tried to tweak the AppDelegate.m, I deleted my build folders and recompiled
My AppDelegate.m file looks like this
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <ReactNativeNavigation/ReactNativeNavigation.h>
#import <RNGoogleSignin/RNGoogleSignin.h>
#import <Firebase.h>
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Firebase configurations
[FIRApp configure];
// Facebook SDK
[[FBSDKApplicationDelegate sharedInstance] application:application
didFinishLaunchingWithOptions:launchOptions];
NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:#"index" fallbackResource:nil];
[ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions];
return YES;
}
// RNGoogleSignin.h -> https://github.com/react-native-community/react-native-google-signin/blob/master/docs/ios-guide.md#modify-your-app-to-respond-to-the-url-scheme-optional
- (BOOL)application:(UIApplication *)application openURL:(nonnull NSURL *)url options:(nonnull NSDictionary<NSString *,id> *)options {
return [RNGoogleSignin application:application
openURL:url
sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
annotation:options[UIApplicationOpenURLOptionsAnnotationKey]];
}
// FACEBOOK SDK
- (BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {
BOOL handled = [[FBSDKApplicationDelegate sharedInstance] application:application
openURL:url
sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey]
annotation:options[UIApplicationOpenURLOptionsAnnotationKey]
];
// Add any custom logic here.
return handled;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
[FBSDKAppEvents activateApp];
}
- (BOOL)application:(UIApplication *)app
openURL:(NSURL *)url
options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
{
if ([[FBSDKApplicationDelegate sharedInstance] application:app openURL:url options:options]) {
return YES;
}
if ([RCTLinkingManager application:app openURL:url options:options]) {
return YES;
}
return NO;
}
#end
this is the entire error popping on the simulator screen instead of the app launching:
Exception '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[0]' was thrown while invoking getImageForFont on target RNVectorIconsManager with params (
Entypo,
"\Uf241",
30,
4278190080,
35
)
callstack: (
0 CoreFoundation 0x0000000111f926fb __exceptionPreprocess + 331
1 libobjc.A.dylib 0x000000011097eac5 objc_exception_throw + 48
2 CoreFoundation 0x0000000111ee0ddc _CFThrowFormattedException + 194
3 CoreFoundation 0x0000000111ffec31 -[__NSPlaceholderDictionary initWithObjects:forKeys:count:] + 321
4 CoreFoundation 0x0000000111f8e3db +[NSDictionary dictionaryWithObjects:forKeys:count:] + 59
5 madilist_app 0x000000010d8339bf -[RNVectorIconsManager createAndSaveGlyphImage:withFont:withFilePath:withColor:] + 415
6 madilist_app 0x000000010d833d68 -[RNVectorIconsManager getImageForFont:withGlyph:withFontSize:withColor:callback:] + 360
7 CoreFoundation 0x0000000111f994cc __invoking___ + 140
8 CoreFoundation 0x0000000111f96a45 -[NSInvocation invoke] + 325
9 CoreFoundation 0x0000000111f96e96 -[NSInvocation invokeWithTarget:] + 54
10 madilist_app 0x000000010d528fba -[RCTModuleMethod invokeWithBridge:module:arguments:] + 2810
11 madilist_app 0x000000010d5db096 _ZN8facebook5reactL11invokeInnerEP9RCTBridgeP13RCTModuleDatajRKN5folly7dynamicE + 790
12 madilist_app 0x000000010d5daba3 _ZZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEiENK3$_0clEv + 131
13 madilist_app 0x000000010d5dab19 ___ZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEi_block_invoke + 25
14 libdispatch.dylib 0x000000011497accf _dispatch_call_block_and_release + 12
15 libdispatch.dylib 0x000000011497bd02 _dispatch_client_callout + 8
16 libdispatch.dylib 0x0000000114982720 _dispatch_lane_serial_drain + 705
17 libdispatch.dylib 0x0000000114983261 _dispatch_lane_invoke + 398
18 libdispatch.dylib 0x000000011498bfcb _dispatch_workloop_worker_thread + 645
19 libsystem_pthread.dylib 0x0000000114d5d611 _pthread_wqthread + 421
20 libsystem_pthread.dylib 0x0000000114d5d3fd start_wqthread + 13
)
RCTFatal
facebook::react::invokeInner(RCTBridge*, RCTModuleData*, unsigned int, folly::dynamic const&)
facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int)::$_0::operator()() const
invocation function for block in facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int)
_dispatch_call_block_and_release
_dispatch_client_callout
_dispatch_lane_serial_drain
_dispatch_lane_invoke
_dispatch_workloop_worker_thread
_pthread_wqthread
start_wqthread

CoreAnimation uncommitted CATranaction NSComboBox

I am populating an NSComboBox with some data from the function below. After it is populated and I try to scroll through the items I get the CATransaction warning. Can anyone shed some light on why this is happening and what I can do to fix it? I have figured out that it may have something to do with changing the UI of the combobox on a thread other than the main thread but after that I am stuck.
func getAllRecords()
{
CATransaction.begin()
let url = NSURL(string: "http://URL.php")
let task = NSURLSession.sharedSession().dataTaskWithURL(url!)
{
(data, response, error) in
var d = NSString(data: data, encoding: NSUTF8StringEncoding)
var arr = d!.componentsSeparatedByString("<") // spliting the incoming string from "<" operator because before that operator is our required data and storing in array
var dataWeNeed:NSString = arr[0] as! NSString // arr[0] is the data before "<" operator and arr[1] is actually no use for us
if let data = NSJSONSerialization.JSONObjectWithData(dataWeNeed.dataUsingEncoding(NSUTF8StringEncoding)!, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSArray
{
for dd in data
{
var name : String = dd["Name"]! as! String
var email : String = dd["Email"]! as! String
//println("Name: \(name)")
//println("Email: \(email)")
self.userComboBox.addItemsWithObjectValues([name])
}
}
}
task.resume()
CATransaction.commit()
}
Here is the warning I am getting from the debug area.
2015-06-14 13:54:04.756 Green Time Clock[2150:738395] Unexpected outstanding background CATransaction
CoreAnimation: warning, encountered thread with uncommitted CATransaction; created by:
0 QuartzCore 0x00007fff9ab4d6c2 _ZN2CA11Transaction4pushEv + 312
1 QuartzCore 0x00007fff9ab689a8 _ZN2CA11Transaction15ensure_implicitEv + 276
2 QuartzCore 0x00007fff9ab4d842 _ZN2CA11Transaction9set_valueEj12_CAValueTypePKv + 40
3 QuartzCore 0x00007fff9ab4f452 +[CATransaction setDisableActions:] + 38
4 AppKit 0x00007fff921a1b8c -[NSView(NSInternal) _updateLayerGeometryFromView] + 389
5 AppKit 0x00007fff921c7d09 -[NSView setFrameSize:] + 1129
6 AppKit 0x00007fff921c789a -[NSControl setFrameSize:] + 77
7 AppKit 0x00007fff922e3891 -[NSTableView setFrameSize:] + 256
8 AppKit 0x00007fff922e35f9 -[NSTableView _tileAndRedisplayAll] + 180
9 Green Time Clock 0x00000001000042d6 _TFFC16Green_Time_Clock14ViewController13getAllRecordsFS0_FT_T_U_FTGSQCSo6NSData_GSQCSo13NSURLResponse_GSQCSo7NSError__T_ + 2886
10 Green Time Clock 0x0000000100004463 _TTRXFo_oGSQCSo6NSData_oGSQCSo13NSURLResponse_oGSQCSo7NSError__dT__XFo_iTGSQS__GSQS0__GSQS1____iT__ + 51
11 Green Time Clock 0x0000000100001e31 _TPA__TTRXFo_oGSQCSo6NSData_oGSQCSo13NSURLResponse_oGSQCSo7NSError__dT__XFo_iTGSQS__GSQS0__GSQS1____iT__ + 81
12 Green Time Clock 0x0000000100004493 _TTRXFo_iTGSQCSo6NSData_GSQCSo13NSURLResponse_GSQCSo7NSError___iT__XFo_oGSQS__oGSQS0__oGSQS1___dT__ + 35
13 Green Time Clock 0x00000001000044fa _TTRXFo_oGSQCSo6NSData_oGSQCSo13NSURLResponse_oGSQCSo7NSError__dT__XFdCb_dGSQS__dGSQS0__dGSQS1___dT__ + 90
14 CFNetwork 0x00007fff8c09cba2 __49-[__NSCFLocalSessionTask _task_onqueue_didFinish]_block_invoke + 157
15 Foundation 0x00007fff9a75f7e8 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
Not sure what root issue is, I found that warning when updating string value to a NSTextView object and resolved it with following code just now.
Just make sure the updating process is handled in main thread.
// Link: NSTextStorage limitation on size and frequency of updates
dispatch_block_t block = ^ {
NSAttributedString *attributeString = [[NSAttributedString alloc] initWithString:[NSString stringWithFormat:#"%#\n", strLog]];
NSTextStorage* store = [_textViewOutputLog textStorage];
[store beginEditing];
[store appendAttributedString:attributeString];
[store endEditing];
[_textViewOutputLog scrollRangeToVisible:NSMakeRange([[_textViewOutputLog string] length], 0)];
};
if ([NSThread isMainThread]) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}

IOS Simulator keeps crashing?

Whenever I try to Run the IOS Simulator, it keeps crashing. I work on Xcode 5.0.2. On the main.m file it says
Thread 1:SIGABRT. Heres is the line where the SIGABRT appeared.
return UIApplicationMain(argc, argv, nil, NSStringFromClass([xyzAppDelegate class]));
heres what was going on in the main.m
#import <UIKit/UIKit.h>
#import "xyzAppDelegate.h"
int main(int argc, char * argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([xyzAppDelegate class]));
}
}
xyzAppDelegate.h
#import <UIKit/UIKit.h>
#interface xyzAppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
xyzAppDelegate.m
#import "xyzAppDelegate.h"
#implementation xyzAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application
{
}
- (void)applicationDidEnterBackground:(UIApplication *)application
{
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
}
- (void)applicationWillTerminate:(UIApplication *)application
{
}
#end
Here is what it shows on the debug area
2014-02-13 00:06:47.933 ToDoList[707:70b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Could not load NIB in bundle: 'NSBundle </Users/garibaldi/Library/Application Support/iPhone Simulator/7.0.3/Applications/8B1ABBAB-D173-4A8E-80AC-8DEA44C5EDE8/ToDoList.app> (loaded)' with name 'Main''
*** First throw call stack:
(
0 CoreFoundation 0x0174c5e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x014bb8b6 objc_exception_throw + 44
2 CoreFoundation 0x0174c3bb +[NSException raise:format:] + 139
3 UIKit 0x004ca39c -[UINib instantiateWithOwner:options:] + 951
4 UIKit 0x004cc2fb -[NSBundle(UINSBundleAdditions) loadNibNamed:owner:options:] + 165
5 UIKit 0x002293bb -[UIApplication _loadMainNibFileNamed:bundle:] + 58
6 UIKit 0x002296e9 -[UIApplication _loadMainInterfaceFile] + 245
7 UIKit 0x0022828f -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 543
8 UIKit 0x0023c87c -[UIApplication handleEvent:withNewEvent:] + 3447
9 UIKit 0x0023cde9 -[UIApplication sendEvent:] + 85
10 UIKit 0x0022a025 _UIApplicationHandleEvent + 736
11 GraphicsServices 0x036df2f6 _PurpleEventCallback + 776
12 GraphicsServices 0x036dee01 PurpleEventCallback + 46
13 CoreFoundation 0x016c7d65 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
14 CoreFoundation 0x016c7a9b __CFRunLoopDoSource1 + 523
15 CoreFoundation 0x016f277c __CFRunLoopRun + 2156
16 CoreFoundation 0x016f1ac3 CFRunLoopRunSpecific + 467
17 CoreFoundation 0x016f18db CFRunLoopRunInMode + 123
18 UIKit 0x00227add -[UIApplication _run] + 840
19 UIKit 0x00229d3b UIApplicationMain + 1225
20 ToDoList 0x0000219d main + 141
21 libdyld.dylib 0x01d7670d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
I tried following Apple's First Tutorial. Sorry if I'm not clear enough, I'm still kinda new here.
Try resetting the simulator.
I'm sorry I cannot yet upload images, but:
(If simulator is not running)
In XCode, go to XCode menu (one left of 'File') on top, 'Open Developer Tool' > 'iOS Simulator'.
In the simulator, click on the 'iOS Simulator menu' > 'Rest Content And Settings...'
Try resetting the simulator (as in #bauerMusic's answer) and then restart your Mac. That consistently fixes a similar issue I have.

parent/child MOC with async disc saving got freeze main queue on osx

I have currently try to implement scheme:
MOC1 (PrivateQueue) -parent-> MOC2 (MainQueue) -parent-> MOC3 (PrivateQueue), PSC to save
here is init code (MOC2 & MOC#:
_writeManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
_writeManagedObjectContext.persistentStoreCoordinator = coordinator;
_writeManagedObjectContext.undoManager = nil;
_mainManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
_mainManagedObjectContext.undoManager = nil;
_mainManagedObjectContext.parentContext = _writeManagedObjectContext;
Here is init MOC1:
_mocSSchild = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
_mocSSchild.undoManager = nil;
_mocSSchild.parentContext = delegateMain.mainManagedObjectContext;
Here is a save:
NSError *error = nil;
[self.mocSSchild obtainPermanentIDsForObjects:self.mocSSchild.insertedObjects.allObjects error:&error];
if (![self.mocSSchild save: &error]) {
NSLog(#"Failed to save to FIRST data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0)
{
for(NSError* detailedError in detailedErrors)
{
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
}
else
{
NSLog(#" %#", [error userInfo]);
}
}
AppDelegate *delegateMain = (AppDelegate *)[[NSApplication sharedApplication] delegate];
if ([delegateMain.mainManagedObjectContext hasChanges] && ![delegateMain.mainManagedObjectContext save: &error]) { NSLog(#"Failed to save to FIRST data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0)
{
for(NSError* detailedError in detailedErrors)
{
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
}
else
{
NSLog(#" %#", [error userInfo]);
}
}
if ([delegateMain.writeManagedObjectContext hasChanges] && ![delegateMain.writeManagedObjectContext save: &error]) { NSLog(#"Failed to save to FIRST data store: %#", [error localizedDescription]);
NSArray* detailedErrors = [[error userInfo] objectForKey:NSDetailedErrorsKey];
if(detailedErrors != nil && [detailedErrors count] > 0)
{
for(NSError* detailedError in detailedErrors)
{
NSLog(#" DetailedError: %#", [detailedError userInfo]);
}
}
else
{
NSLog(#" %#", [error userInfo]);
}
}
All fetch requests is placed in right block (and of course i never touch mainManagedObjectContext to execute fetch requests):
__block NSError *error = nil;
__block NSArray *findedResult = nil;
[self.mocSSchild performBlockAndWait:^{
findedResult = [self.mocSSchild executeFetchRequest:fetchRequest error:&error];
}];
After one save i have freezing in main queue (looks like core data try to execute fetch request on mainManagedObjectContext where i don't do requests):
Call graph:
2633 Thread_803320 DispatchQueue_173: NSManagedObjectContext Queue (serial)
+ 2633 start (in libdyld.dylib) + 1 [0x7fff8bb907e1]
+ 2633 main (in callsfreecall) + 34 [0x10992c202]
+ 2633 NSApplicationMain (in AppKit) + 869 [0x7fff8a49cbd6]
+ 2633 -[NSApplication run] (in AppKit) + 517 [0x7fff8a4f81a3]
+ 2633 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] (in AppKit) + 128 [0x7fff8a500df2]
+ 2633 _DPSNextEvent (in AppKit) + 685 [0x7fff8a501533]
+ 2633 BlockUntilNextEventMatchingListInMode (in HIToolbox) + 62 [0x7fff8f356ae3]
+ 2633 ReceiveNextEventCommon (in HIToolbox) + 356 [0x7fff8f356c52]
+ 2633 RunCurrentEventLoopInMode (in HIToolbox) + 209 [0x7fff8f356eb4]
+ 2633 CFRunLoopRunSpecific (in CoreFoundation) + 290 [0x7fff9526c0e2]
+ 2633 __CFRunLoopRun (in CoreFoundation) + 1644 [0x7fff9526cb4c]
+ 2633 _dispatch_main_queue_callback_4CF (in libdispatch.dylib) + 275 [0x7fff8c4c20c8]
+ 2633 _dispatch_client_callout (in libdispatch.dylib) + 8 [0x7fff8c4bd0b6]
+ 2633 _dispatch_barrier_sync_f_slow_invoke (in libdispatch.dylib) + 77 [0x7fff8c4c2a2d]
+ 2633 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0 (in CoreData) + 533 [0x7fff93d8b6c5]
+ 2633 -[NSManagedObjectContext countForFetchRequest:error:] (in CoreData) + 1563 [0x7fff93d65ddb]
+ 2633 -[NSManagedObjectContext(_NSInternalAdditions) _countWithNoChangesForRequest:error:] (in CoreData) + 298 [0x7fff93d65f4a]
+ 2633 -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] (in CoreData) + 354 [0x7fff93d576c2]
+ 2633 _perform (in CoreData) + 172 [0x7fff93d5787c]
+ 2633 _dispatch_barrier_sync_f_invoke (in libdispatch.dylib) + 39 [0x7fff8c4be723]
+ 2633 _dispatch_client_callout (in libdispatch.dylib) + 8 [0x7fff8c4bd0b6]
+ 2633 __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0 (in CoreData) + 533 [0x7fff93d8b6c5]
+ 2633 -[NSManagedObjectContext countForFetchRequest:error:] (in CoreData) + 1563 [0x7fff93d65ddb]
+ 2633 -[NSManagedObjectContext(_NSInternalAdditions) _countWithNoChangesForRequest:error:] (in CoreData) + 298 [0x7fff93d65f4a]
+ 2633 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] (in CoreData) + 1138 [0x7fff93d10ba2]
+ 2633 -[_PFLock lock] (in CoreData) + 24 [0x7fff93cfe548]
+ 2633 pthread_mutex_lock (in libsystem_c.dylib) + 536 [0x7fff92797dfd]
+ 2633 __psynch_mutexwait (in libsystem_kernel.dylib) + 10 [0x7fff938ca122]
First, you need to do something with errors when you receive them. Right now you are not doing anything, not logging them, not reacting to them, nothing. This is bad. When an error occurs you have no indication of it at all. You just go onto the next step.
Second, you are saving all of your MOCs on the same queue. Any activity against a private MOC must be performed inside of a block via the -performBlock: or -performBlockAndWait: methods.
Third, there is no indication what queue you are running on.
Your import MOC should be running inside of an operation or a block running async. The import MOC should be using thread confinement instead of being a private MOC. Once the import MOC has completed its work it should save itself and then indicate to the main queue that the main MOC should be saved.
The main MOC should only be saved on the main queue. When the main MOC has completed its save then it should fire off a save to the top level MOC via its -performBlock:.
Correct your issues with the error results and take a look at what queues you are doing the work on. If everything is on the main queue then parent/child MOCs is not going to solve your problem. You need to rethink what work is being performed where.
Update 1
First, you can detect the errors by listening to the results from the calls. If the call returns a BOOL then that is a pass/fail. If the call returns something else then if that something else is nil then that is a failure and the error will be present.
As for your code, no it is not correct. You have threading issues as I mentioned. You are touching a private MOC directly, that is incorrect. There are probably other errors but I cannot see them based on this code.
Your "writing" MOC should only be touched via a -performBlock: or -performBlockAndWait:. In this case you should be using a -performBlock:. You are touching it directly. That is bad.
Your main MOC should only be touched on the main queue or via a -performBlock:/-performBlockAndWait:. You appear to be touching it directly in this code.
You are accessing your appDelegate as a singleton. This is a bad code smell. Look up and start using dependency injection.
Your child moc is set up as a private when it should be a thread confined context and then it should only be accessed on the thread that created it which ideally should be in an NSOperation.
In short, there is a lot of core concepts that you are missing here. You need to understand how parent/child contexts work and you need to have a better understanding of queues and threads before you attempt to develop code like this.

__NSCFString appendString: crash for NSMutableString in Cocoa

I have been facing this issue and I admit that I lack of some fundamental concepts of memory managements. I've not been able to solve this and trust me, I've been trying so many things out.
In my app, there are 4 threads (can be up to 12 threads in future) which will read from RS232 ports. In each thread (threadRS232Read), I'll append the RS232 characters into respective NSMutableString using appendString. the NSMutableString will grow incredibly large with the appendString until a full test is completed. And periodically inside a test, clearRdBuffStr is called to clear the string. The app always crashes in appendString. If I get lucky, I can run few tests but normally, it crashes on the first run. Below are the code snippets and the crash log.
AppController.h
...
`#interface AppController : NSObject {
...
NSMutableString *buffStr1, *buffStr2, *buffStr3, *buffStr4;
...}
AppController.m
...
//in -(id)init
buffStr1 = [[NSMutableString alloc] initWithString:#""];
buffStr2 = [[NSMutableString alloc] initWithString:#""];
buffStr3 = [[NSMutableString alloc] initWithString:#""];
buffStr4 = [[NSMutableString alloc] initWithString:#""];
...
// in -(void)dealloc
[buffStr1 release];
[buffStr2 release];
[buffStr3 release];
[buffStr4 release];`
In another file RS232RW.m, a thread will be used to update buffStr1 to 4
RS232RW.m
- (void)threadRS232Read:(id)argument {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
....
//read from RS232 port buffer and etc...
NSString *buffStr = [NSString stringWithUTF8String:buff];
switch (portNo) {
case 0:
if (buffStr != nil)
{
[buffStr1 appendString:buffStr];
}
break;
case 1:
if (buffStr != nil)
{
[buffStr2 appendString:buffStr];
}
break;
case 2:
if (buffStr != nil)
{
[buffStr3 appendString:buffStr];
}
break;
case 3:
if (buffStr != nil)
{
[buffStr4 appendString:buffStr];
}
break;
case 4:
if (buffStr != nil)
{
[buffStr5 appendString:buffStr];
}
break;
....
// clearRdBuffStr will be called by the other part of the program to clear this buffer.
-(void) clearRdBuffStr:(int) portNo {
switch (portNo) {
case 0:
[buffStr1 setString:#""];
break;
case 1:
[buffStr2 setString:#""];
break;
case 2:
[buffStr3 setString:#""];
break;
case 3:
[buffStr4 setString:#""];
break;
....
The app always crashes at 1 of the appendString above.
The crash log is as below:
....
Crashed Thread: 3
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Application Specific Information:
objc[584]: garbage collection is OFF
*** error for object 0x6d02b600: double free
....
Thread 3 Crashed:
0 libsystem_kernel.dylib 0x905819c6 __pthread_kill + 10
1 libsystem_c.dylib 0x926ecf78 pthread_kill + 106
2 libsystem_c.dylib 0x926ddbdd abort + 167
3 libsystem_c.dylib 0x92701508 szone_error + 333
4 libsystem_c.dylib 0x92702dd1 free_small_botch + 102
5 com.apple.CoreFoundation 0x97ee51e8 __CFAllocatorSystemDeallocate + 24
6 com.apple.CoreFoundation 0x97ee51ba CFAllocatorDeallocate + 266
7 com.apple.CoreFoundation 0x97ee50a2 __CFStrDeallocateMutableContents + 178
8 com.apple.CoreFoundation 0x97ee422b __CFStringChangeSizeMultiple + 3147
9 com.apple.CoreFoundation 0x97f86010 __CFStringCheckAndReplace + 496
10 com.apple.CoreFoundation 0x97f95dad -[__NSCFString appendString:] + 45
11 com.TopTestDFU 0x00109f6d -[AppController(RS232RW)
threadRS232Read:] + 752
12 com.apple.Foundation 0x92aabf7d -[NSThread main] + 45
13 com.apple.Foundation 0x92aabf2d __NSThread__main__ + 1582
14 libsystem_c.dylib 0x926eaed9 _pthread_start + 335
15 libsystem_c.dylib 0x926ee6de thread_start + 34
The Cocoa mutable objects such as NSMutableString are not thread safe. It's up to you to arrange synchronisation using some form of lock.
Check out NSLock for one option.
You might try making the 4 NSMutableStrings into atomic properties rather than ivars. It might work in this case, although atomic doesn't actually guarantee thread safety.
[edit]
... actually, if in your case, you are sure that each thread is using a different port number, then it's probably not the NSMutableStrings as such that are the problem. It's probably NSString *buffStr = [NSString stringWithUTF8String:buff]; is being called by one thread before another has finished appending buffStr. So you need a lock around the that as well as the append.

Resources