Duncan Groenewald
Duncan Groenewald

Reputation: 9018

Does anyone know whats going on here ? Core Data / iCloud

So whats happening here is the app has just received the NSPersistentStoreDidImportUbiquitousContentChangesNotification, and I have just called

- (void)storesDidUpdate:(NSNotification*)note {
    FLOG(@"storesDidUpdate ");
    [_managedObjectContext mergeChangesFromContextDidSaveNotification:note];

    // Refresh user Interface
    [[NSNotificationCenter defaultCenter] postNotificationName:@"iProjectCoreDataUpdated"
                                                        object:self];

    [self updateDetails];
}

And now the app is trying to update a UITextView with a fresh copy of text by simply doing the following:

self.detailText.attributedText  = [self.detailItem valueForKey:@"scope"];

Where detailItem is a NSManagedObject retrieved prior to receiving the update from iCloud.

Not sure why the textContainer is complaining or what its complaining about, and also not sure why importing logs is happening because I have already received a notification that its done!

Strangely other UITableViews update correctly if I just call reloadData.

Any ideas on whether I am doing something wrong here? Note that if I don't try and update the textView it works fine and if I close the view and go back to it then I get the correct data.

Also when I restart the app all the data is there, no corruptions or anything, in fact the app seems remarkably robust in most respects when it comes to the Core Data store, despite things blowing up on either side of iCloud!

Oh and the reloadFetchedResults is a bit misleading because I don't seem to need to do that, so the method name is a hangover from the past, all I am doing is refreshing values in the UI in this call.

2013-10-09 07:25:53.783 MyApp[4509:510b] OpeningViewController.reloadFetchedResults: called 2013-10-09 07:25:53.786 MyApp[4509:510b] InfoDetailViewController.reloadFetchedResults: called in InfoDetailViewController 2013-10-09 07:25:53.788 MyApp[4509:510b] * Assertion failure in void _UIPerformResizeOfTextViewForTextContainer(NSLayoutManager *, UIView *, NSTextContainer *, NSUInteger)(), /SourceCache/UIFoundation/UIFoundation-258/UIFoundation/TextSystem/NSLayoutManager_Private.m:1510 2013-10-09 07:25:53.793 MyApp[4509:510b] -_PFUbiquityRecordImportOperation main: CoreData: Ubiquity: Error importing transaction log: transactionLogLocation: : /var/mobile/Library/Mobile Documents/HHHHHHNNNN~com~mycompany~MyApp/CoreData/New Document/duncangroenewald~simAABC628E-9D5E-58F7-9B8D-0BC724C6D0C8/New Document/W8MckEJ0x2d~HZZIeUH2be6hs41TEOONzKIrCuLcuP4=/6C953E7C-B2AF-47F7-B828-DD062B96415D.1.cdt transactionNumber: 5 , exception: Only run on the main thread! User Info: (null) 2013-10-09 07:25:53.803 MyApp[4509:510b] -_PFUbiquityRecordsImporter operation:failedWithError:: CoreData: Ubiquity: Import operation encountered an error: Error Domain=NSCocoaErrorDomain Code=134060 "The operation couldn’t be completed. (Cocoa error 134060.)" UserInfo=0x16d882c0 {exception=Only run on the main thread!} userInfo: { exception = "Only run on the main thread!"; }. While trying to import the log file at the URL: transactionLogLocation: : /var/mobile/Library/Mobile Documents/HHHHHHNNNN~com~mycompany~MyApp/CoreData/New Document/duncangroenewald~simAABC628E-9D5E-58F7-9B8D-0BC724C6D0C8/New Document/W8MckEJ0x2d~HZZIeUH2be6hs41TEOONzKIrCuLcuP4=/6C953E7C-B2AF-47F7-B828-DD062B96415D.1.cdt transactionNumber: 5 2013-10-09 07:25:53.809 MyApp[4509:510b] * Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Only run on the main thread!' *** First throw call stack: (0x2ff23f53 0x3a6996af 0x2ff23e2d 0x308cb1df 0x3796643d 0x37966185 0x3798f7bb 0x379926f7 0x37992759 0x379b378b 0x379b331f 0x379b2f0d 0x3273b05d 0x129717 0x2fee6121 0x2fe5a317 0x3083edcd 0x308436ab 0x118263 0x2fee6121 0x2fe5a317 0x2fd8c69f 0x2fd8cc93 0x2fd813dd 0x3085197b 0x308f5b35 0x3ab83297 0x3ab8309b 0x3ab83d15 0x3ab83f8d 0x3acbedbf 0x3acbec84) libc++abi.dylib: terminating with uncaught exception of type NSException

EDIT: I have posted some sample Core Data/iCloud apps for iOS and OSX here - they include background threads for loading/deleting data as well as iCloud sync. Hopefully address the issue described here. http://ossh.com.au/design-and-technology/software-development/sample-library-style-ios-core-data-app-with-icloud-integration/

Upvotes: 5

Views: 4183

Answers (4)

Duncan Groenewald
Duncan Groenewald

Reputation: 9018

Yes, I get that but I don't do anything on any threads so something else must be. I am updating a UITextView and I guess its possible something in that is causing a failure. I am not clear on why this would have anything to do with the ubiquityImporter - perhaps someone who can interpret this stuff below can point me in the right direction. Am I somehow running something on the wrong thread ?

First throw call stack:
(
    0   CoreFoundation                      0x027c55e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x019238b6 objc_exception_throw + 44
    2   CoreFoundation                      0x027c5448 +[NSException raise:format:arguments:] + 136
    3   Foundation                          0x01062960 -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 101
    4   UIFoundation                        0x01b33131 -[NSLayoutManager(NSPrivate) _resizeTextViewForTextContainer:] + 419
    5   UIFoundation                        0x01b32e16 -[NSLayoutManager(NSPrivate) _recalculateUsageForTextContainerAtIndex:] + 2083
    6   UIFoundation                        0x01b67675 _enableTextViewResizing + 234
    7   UIFoundation                        0x01b6b275 -[NSLayoutManager textStorage:edited:range:changeInLength:invalidatedRange:] + 688
    8   UIFoundation                        0x01b6b2fa -[NSLayoutManager processEditingForTextStorage:edited:range:changeInLength:invalidatedRange:] + 82
    9   UIFoundation                        0x01b93d35 -[NSTextStorage _notifyEdited:range:changeInLength:invalidatedRange:] + 153
    10  UIFoundation                        0x01b93870 -[NSTextStorage processEditing] + 462
    11  UIFoundation                        0x01b93419 -[NSTextStorage endEditing] + 80
    12  UIFoundation                        0x01b934a3 -[NSTextStorage coordinateEditing:] + 66
    13  UIKit                               0x007f4f48 -[UITextView setAttributedText:] + 254
    14  MyApp                        0x00027d7a -[WBSDetailViewController displayItem] + 3146
    15  MyApp                        0x00028c6c -[WBSDetailViewController refreshUI:] + 156
    16  Foundation                          0x01088e39 __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke + 40
    17  CoreFoundation                      0x02821524 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20
    18  CoreFoundation                      0x0277907b _CFXNotificationPost + 2859
    19  Foundation                          0x00fc2b91 -[NSNotificationCenter postNotificationName:object:userInfo:] + 98
    20  Foundation                          0x00fd206a -[NSNotificationCenter postNotificationName:object:] + 55
    21  MyApp                        0x00031095 -[BaseAppDelegate storesDidUpdate:] + 293
    22  Foundation                          0x01088e39 __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke + 40
    23  CoreFoundation                      0x02821524 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 20
    24  CoreFoundation                      0x0277907b _CFXNotificationPost + 2859
    25  Foundation                          0x00fddd7b -[NSNotificationCenter postNotification:] + 121
    26  CoreData                            0x0173c5f4 -[_PFUbiquityRecordsImporter postImportNotificationForStoreName:andLocalPeerID:withUserInfo:] + 1892
    27  CoreData                            0x0173cbc2 -[_PFUbiquityRecordsImporter operationDidFinish:] + 706
    28  CoreData                            0x0172e8ce -[_PFUbiquityRecordImportOperation main] + 15102
    29  Foundation                          0x0108aa69 -[__NSOperationInternal _start:] + 671
    30  Foundation                          0x01007798 -[NSOperation start] + 83
    31  Foundation                          0x0108cd34 __NSOQSchedule_f + 62
    32  libdispatch.dylib                   0x05b794b0 _dispatch_client_callout + 14
    33  libdispatch.dylib                   0x05b67088 _dispatch_queue_drain + 450
    34  libdispatch.dylib                   0x05b66e85 _dispatch_queue_invoke + 126
    35  libdispatch.dylib                   0x05b67e25 _dispatch_root_queue_drain + 83
    36  libdispatch.dylib                   0x05b6813d _dispatch_worker_thread2 + 39
    37  libsystem_pthread.dylib             0x05f05dab _pthread_wqthread + 336
    38  libsystem_pthread.dylib             0x05f09cce start_wqthread + 30
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Upvotes: 0

Alex Cio
Alex Cio

Reputation: 6052

I got the same problem. It was exactly the issue @John Rogers explained. I created UITextViews and in the background I called a URL to get some data which should be inserted into my generated UITextViews. But the Problem was the method sendAsynchronousRequest which will be called in background and cause the crash in my case.

I could solve the problem by performing the specific selector on main thread when receiving my data. So maybe you can insert you're method call into another method and call it this way:

[self performSelectorOnMainThread:@selector(received:) 
                       withObject:data 
                    waitUntilDone:YES];

This way you get back to the main thread again.

Upvotes: 3

Duncan Groenewald
Duncan Groenewald

Reputation: 9018

OK here is what seems to fix it - I guess I never realised that receiving a notification would run on another thread. Is that normal behaviour, are all Core Data notifications you receive called on a background thread ? If so do you always have to make sure anything you do is then running on the correct thread ?

- (void)storesDidUpdate:(NSNotification*)note {
    FLOG(@"storesDidUpdate ");
    [_managedObjectContext mergeChangesFromContextDidSaveNotification:note];

    [[NSOperationQueue mainQueue] addOperationWithBlock:^ {
        //Your code goes in here
        LOG(@" Main Thread Code");

        // Refresh user Interface
        [[NSNotificationCenter defaultCenter] postNotificationName:@"CoreDataUpdatedNotification"
                                                        object:self];
    }];

}

EDIT:

I have finally gotten around to documenting how I got Core Data and iCloud to work pretty reliably, including handling moving to and from iCloud in response to the use changing their Use iCloud preference settings. I was unable to find a good explanation with working code when I was trying to figure out how to get it working so I hope this proves useful to others. Included is a video of the app working so you can see how it behaves to help you figure out if it's what you are wanting to achieve.

http://ossh.com.au/design-and-technology/software-development/

Upvotes: 9

Eric Risler
Eric Risler

Reputation: 319

Reading all the answers+comments (and your fix) - I think it should be noted you MUST update any UI control from the main thread only.

I assume the [self updateDetails]; calls the self.detailText.attributedText = [self.detailItem valueForKey:@"scope"]; code?...which is the actual code that updates the UI?

Assume that, then You could execute the call to -updateDetails using -performSelectorOnMainThread: or in the -updateDetails check that you are executing on the main thread ([NSThread isMainThread]) and wrap the UI update code there so the caller doesn't care what thread they call -updateDetails from.

Upvotes: 0

Related Questions