CoreAnimation uncommitted CATranaction NSComboBox - xcode

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);
}

Related

Trying build a note app, Xcode 8, get this error

I've been following a tutorial (outdated as it says) and I'm trying to build my first note app. Unfortunately it is terminated before it even runs. Any help would be much appreciated. This is the code and at the end the crash-report. Cheers !
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Saves changes in the application's managed object context before the application terminates.
self.saveContext()
}
// MARK: - Core Data stack
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "ToDo")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
// MARK: - Core Data Saving support
func saveContext () {
let context = persistentContainer.viewContext
if context.hasChanges {
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
}
This is the crash report I get
2017-05-14 21:04:58.079 ToDo[17123:3603269] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'must pass a class of kind UITableViewCell'
*** First throw call stack:
(
0 CoreFoundation 0x000000010fcbdb0b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010cb39141 objc_exception_throw + 48
2 CoreFoundation 0x000000010fd26625 +[NSException raise:format:] + 197
3 UIKit 0x000000010d57fdde -[UITableView registerClass:forCellReuseIdentifier:] + 284
4 ToDo 0x000000010c5597db _TFC4ToDo14ViewController11viewDidLoadfT_T_ + 571
5 ToDo 0x000000010c5598e2 _TToFC4ToDo14ViewController11viewDidLoadfT_T_ + 34
6 UIKit 0x000000010d5c2cca -[UIViewController loadViewIfRequired] + 1235
7 UIKit 0x000000010d601b1c -[UINavigationController _layoutViewController:] + 56
8 UIKit 0x000000010d6023fa -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 466
9 UIKit 0x000000010d60256b -[UINavigationController _startTransition:fromViewController:toViewController:] + 127
10 UIKit 0x000000010d6036b3 -[UINavigationController _startDeferredTransitionIfNeeded:] + 843
11 UIKit 0x000000010d6047f1 -[UINavigationController __viewWillLayoutSubviews] + 58
12 UIKit 0x000000010d7f62bc -[UILayoutContainerView layoutSubviews] + 231
13 UIKit 0x000000010d4e320b -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1268
14 QuartzCore 0x0000000112aa5904 -[CALayer layoutSublayers] + 146
15 QuartzCore 0x0000000112a99526 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 370
16 QuartzCore 0x0000000112a993a0 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
17 QuartzCore 0x0000000112a28e92 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
18 QuartzCore 0x0000000112a55130 _ZN2CA11Transaction6commitEv + 468
19 QuartzCore 0x0000000112a55b37 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 115
20 CoreFoundation 0x000000010fc63717 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
21 CoreFoundation 0x000000010fc63687 __CFRunLoopDoObservers + 391
22 CoreFoundation 0x000000010fc48038 CFRunLoopRunSpecific + 440
23 UIKit 0x000000010d41a02f -[UIApplication _run] + 468
24 UIKit 0x000000010d4200d4 UIApplicationMain + 159
25 ToDo 0x000000010c55d077 main + 55
26 libdyld.dylib 0x0000000110c5d65d start + 1
27 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

Swift + Parse: 'Can't use nil for keys or values on PFObject. Use NSNull for values.'

So I have a Swift application that I am working on (in Xcode 7.3).
It uses Parse and in it I have a function that is generating the error message stated in the title.
The code appears as follows;
#IBAction func callUber(sender: AnyObject) {
let riderRequest = PFObject(className:"riderRequest")
riderRequest["username"] = PFUser.currentUser()?.username
riderRequest["location "] = PFGeoPoint(latitude:latitude, longitude:longitude)
riderRequest.saveInBackgroundWithBlock {
(success: Bool, error: NSError?) -> Void in
if (success) {
self.callUberButton.setTitle("Cancel Uber", forState: UIControlState.Normal)
} else {
let alert = UIAlertController(title: "Could not call Uber", message: "Please try again", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
}
}
Now somewhere in this code nil is being applied to a value, and this causes the error message (or so I think). I have been looking around on SO for solutions to this problem, however I could not find any similar threads for this error message and Swift, only Objective-C.
I'm guessing that I have to introduce some sort of error handling or check where I make sure that the value of the object is not nil, however I cant seem to figure out where, or how to apply this.
The error is only triggered when I press the "callUber" button, and the full output from the debug console follows below.
2016-04-15 12:21:01.900 ParseStarterProject-Swift[8781:2591354] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Can't use nil for keys or values on PFObject. Use NSNull for values.'
*** First throw call stack:
(
0 CoreFoundation 0x000000010ca98d85 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010eca0deb objc_exception_throw + 48
2 CoreFoundation 0x000000010ca98cbd +[NSException raise:format:] + 205
3 ParseStarterProject-Swift 0x000000010c1042a8 -[PFObject(Private) _setObject:forKey:onlyIfDifferent:] + 122
4 ParseStarterProject-Swift 0x000000010c107d01 -[PFObject setObject:forKey:] + 53
5 ParseStarterProject-Swift 0x000000010c107d46 -[PFObject setObject:forKeyedSubscript:] + 50
6 ParseStarterProject-Swift 0x000000010c0c847f _TFC25ParseStarterProject_Swift19RiderViewController8callUberfPs9AnyObject_T_ + 671
7 ParseStarterProject-Swift 0x000000010c0c89d6 _TToFC25ParseStarterProject_Swift19RiderViewController8callUberfPs9AnyObject_T_ + 54
8 UIKit 0x000000010d726a8d -[UIApplication sendAction:to:from:forEvent:] + 92
9 UIKit 0x000000010d899e67 -[UIControl sendAction:to:forEvent:] + 67
10 UIKit 0x000000010d89a143 -[UIControl _sendActionsForEvents:withEvent:] + 327
11 UIKit 0x000000010d899263 -[UIControl touchesEnded:withEvent:] + 601
12 UIKit 0x000000010d79999f -[UIWindow _sendTouchesForEvent:] + 835
13 UIKit 0x000000010d79a6d4 -[UIWindow sendEvent:] + 865
14 UIKit 0x000000010d745dc6 -[UIApplication sendEvent:] + 263
15 UIKit 0x000000011dfe0b15 -[UIApplicationAccessibility sendEvent:] + 77
16 UIKit 0x000000010d71f553 _UIApplicationHandleEventQueue + 6660
17 CoreFoundation 0x000000010c9be301 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
18 CoreFoundation 0x000000010c9b422c __CFRunLoopDoSources0 + 556
19 CoreFoundation 0x000000010c9b36e3 __CFRunLoopRun + 867
20 CoreFoundation 0x000000010c9b30f8 CFRunLoopRunSpecific + 488
21 GraphicsServices 0x0000000111eb0ad2 GSEventRunModal + 161
22 UIKit 0x000000010d724f09 UIApplicationMain + 171
23 ParseStarterProject-Swift 0x000000010c0cc712 main + 114
24 libdyld.dylib 0x000000010f7a792d start + 1
25 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
A couple of things that may be the issue:
Double check your class name is "riderRequest", I think "RiderRequest" could possibly be the actual name.
Second is to check all your key names are correct by going to the parse dashboard and having a look at your class
Last thing is to confirm that all your values for things like username and latitude and longitude are not nil before setting them.
Maybe try:
if let username = PFUser.currentUser()?.username && latitude != nil && longitude != nil {
riderRequest.setObject(username, forKey: "username")
riderRequest.setObject(PFGeoPoint(latitude: latitude, longitude: longitude), forKey: "location")
//then run the rest of the code as you have been
}

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.

Mind boggling QTMovie export crash

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.

Resources