Cannot remove an observer <NSArrayController> for the key path "count" - binding

I am getting:
*** Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <NSArrayController> for the key path "count" from <MyElement> because it is not registered as an observer.'
I have a background NSOperation which is populating the properties of MyElement. These MyElement objects are in an array managed by NSArrayController and are bound to a NSTableView.
Could this be related to changing properties on a background thread and if so, how can I disable that so that the table doesn't see those changes until they are complete (and can be updated on the main thread)?
I have it set to sort by a "size" (NSNumber) property and
The crash looks like:
0 CoreFoundation 0x00007fff87ec44f2 __exceptionPreprocess + 178
1 libobjc.A.dylib 0x00007fff85d6cf7e objc_exception_throw + 48
2 CoreFoundation 0x00007fff87f2b4bd +[NSException raise:format:] + 205
3 Foundation 0x00007fff8755d786 -[NSObject(NSKeyValueObserverRegistration) _removeObserver:forProperty:] + 504
4 Foundation 0x00007fff8755d533 -[NSObject(NSKeyValueObserverRegistration) removeObserver:forKeyPath:] + 108
5 Foundation 0x00007fff875ce1a4 -[NSObject(NSKeyValueObserverRegistration)
...
15 Foundation 0x00007fff87572a69 _NSSetObjectValueAndNotify + 274
16 MyApp 0x0000000100051a10 -[MyPropertiesOperation main] + 496

It seems that I can't modify these objects in a background thread, and I see no way to temporarily suspend an observer, so instead I am adding all the properties to a dictionary on the background thread and then on the main thread calling:
[element setValuesForKeysWithDictionary:properties];

Related

Realm, Object has been deleted or invalidated

I am trying to build an new iOS app and am using the RxSwift Library and Realm as database.
I build a tableview which shows a list of object from realm and these object should be editable and can be removed. (I don't use the tableview editing capabilities for this.)
Now when I remove an item from the table the table should refresh because i used RxSwift to bind the tableview to the Realm results. But instead of updating it crashes the app.
The error I get when the app crashes is 'RLMException', reason: 'Object has been deleted or invalidated.'
Also I get a stack trace in the output, but I can't find the source / reason why the crash happens.
Output stacktrace:
2018-05-14 00:09:34.660634+0200 RealmTest[65540:4239839] *** Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated.'
*** First throw call stack:
(
0 CoreFoundation 0x000000010f76e1e6 __exceptionPreprocess + 294
1 libobjc.A.dylib 0x000000010ee03031 objc_exception_throw + 48
2 Realm 0x000000010d44abd3 _ZL17RLMVerifyAttachedP13RLMObjectBase + 83
3 Realm 0x000000010d44c89c _ZN12_GLOBAL__N_18getBoxedIN5realm10StringDataEEEP11objc_objectP13RLMObjectBasem + 28
4 Realm 0x000000010d44c877 ___ZN12_GLOBAL__N_115makeBoxedGetterIN5realm10StringDataEEEP11objc_objectm_block_invoke + 39
5 RealmTest 0x000000010cf9c6a9 _T09RealmTest0B9ModelItemV8identitySSvg + 41
6 RealmTest 0x000000010cf9c6f5 _T09RealmTest0B9ModelItemV14Differentiator16IdentifiableTypeAadEP8identity8IdentityQzvgTW + 21
7 Differentiator 0x000000010d29f24e _T014Differentiator4DiffO23calculateAssociatedData33_D199D3FBF4B7CA3AFA95223EE09B4772LLs15ContiguousArrayVyAGyAC04ItemdE0AELLVGG_AKtAGyAGyxGG07initialP5Cache_AM05finalpR0tKAA16IdentifiableTypeRzlFZ + 2094
8 Differentiator 0x000000010d2ac30e _T014Differentiator4DiffO16CommandGenerator33_D199D3FBF4B7CA3AFA95223EE09B4772LLV22calculateItemMovementss15ContiguousArrayVyAIyAC0N14AssociatedDataAELLVGG_AMtAIyAIy0N0QzGG07initialN5Cache_AQ05finalnU0AIyAC07SectionrS0AELLVG0twS0AV0vwS0tKFZ + 334
9 Differentiator 0x000000010d2a1d65 _T014Differentiator4DiffO16CommandGenerator33_D199D3FBF4B7CA3AFA95223EE09B4772LLV27generatorForInitialSectionsAFy_xGSayxG_AI05finalP0tKFZ + 1253
10 Differentiator 0x000000010d2a1395 _T014Differentiator4DiffO27differencesForSectionedViewSayAA9ChangesetVyxGGSayxG15initialSections_AI05finalI0tKAA26AnimatableSectionModelTypeRzlFZ + 277
11 RxDataSources 0x000000010e35ede4 _T013RxDataSources0a26TableViewSectionedAnimatedB6SourceC05tableE0ySo07UITableE0C_0A5Swift5EventOySayxGG08observedL0tFyACyxG_AJtcfU_yycfU_ + 660
12 RxDataSources 0x000000010e360049 _T013RxDataSources0a26TableViewSectionedAnimatedB6SourceC05tableE0ySo07UITableE0C_0A5Swift5EventOySayxGG08observedL0tFyACyxG_AJtcfU_yycfU_TA + 25
13 RxDataSources 0x000000010e35f63d _T0Ieg_IeyB_TR + 45
14 libdispatch.dylib 0x0000000113b5b807 _dispatch_call_block_and_release + 12
15 libdispatch.dylib 0x0000000113b5c848 _dispatch_client_callout + 8
16 libdispatch.dylib 0x0000000113b6792b _dispatch_main_queue_callback_4CF + 628
17 CoreFoundation 0x000000010f730c99 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
18 CoreFoundation 0x000000010f6f4ea6 __CFRunLoopRun + 2342
19 CoreFoundation 0x000000010f6f430b CFRunLoopRunSpecific + 635
20 GraphicsServices 0x0000000117bb5a73 GSEventRunModal + 62
21 UIKit 0x000000010fbeb0b7 UIApplicationMain + 159
22 RealmTest 0x000000010cf9a0a7 main + 55
23 libdyld.dylib 0x0000000113bd9955 start + 1
24 ??? 0x0000000000000001 0x0 + 1
)
My question is if somebody knows what I do wrong and wat the correct way of removing an realm object is using RxSwift and Databinding?
Edit:
I Made a small test project and put it on my github, it errors when you tab the deleteFirst button. https://github.com/Hiiragisan09/ios-example-project-realm-test
I found the solution my self.
When I started using Realm I didn't know that the object mutates if you delete it.
It was a bit of a struggle because when realm crashes on 'realm object has been deleted or invalidated' it doesn't give a stacktrace of where you tried to access a property of the realmobject.
So when you delete an item from Realm it will trigger the table to get new items, and because the table is animated it will try to diff the new data with the old data. And when the Diff tries to access a property in the old data it will crash.
To fix the problem I created structs that represent the data in the table. So that when I delete a Realm object, the table will not crash because the Diff can still access the old data.
The way I use structs with Realm How to save a struct to realm in swift
I had the same issue. Then I read Martyn's answer. I gave him the upvote because triaging the problem was the hardest part for me. But I implemented a different solution than his. Adding a struct-based repository layer on top of my Realm data-model feels heavy given the scope of the problem.
My lighter-weight solution: I added a parameter to my collectionView reload method to control the reload animation. I default the param to true, and then override it & set it to false as needed. The collectionView doesn't try to access old / deleted Realm objects because it's not trying to animate the old elements off the view. Problem solved.
func displayRecipes(_ recipes: [Recipe], withAnimations: Bool = true) {
...
dataSource?.apply(snapshot, animatingDifferences: withAnimations)
}

Exact line for exception in Xcode

I am new to Xcode and Objective-C. Unlike Android Java exceptions, I didn't find any exact line number where the exception occurred, though function name can be known from the crash log. Following is the crash log:
2014-07-28 17:44:53.814 ExampleApp[82720:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(
0 CoreFoundation 0x034b25e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x028bc8b6 objc_exception_throw + 44
2 CoreFoundation 0x03464bcc -[__NSArrayM insertObject:atIndex:] + 844
3 CoreFoundation 0x03464870 -[__NSArrayM addObject:] + 64
4 ExampleApp 0x0017f99e +[ReportGenerator prepareReportList:] + 5486
5 ExampleApp 0x0017db99 +[ReportGenerator generateReportContent:viewController:] + 73
6 ExampleApp 0x0017b682 +[ReportGenerator generateReport:viewController:style:] + 322
7 ExampleApp 0x000a68fd -[ReportsViewController showReport] + 189
8 libobjc.A.dylib 0x028ce81f -[NSObject performSelector:withObject:] + 70
9 Foundation 0x01fa29d8 __NSThreadPerformPerform + 285
10 CoreFoundation 0x0343b83f __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 15
11 CoreFoundation 0x0343b1cb __CFRunLoopDoSources0 + 235
12 CoreFoundation 0x0345829e __CFRunLoopRun + 910
13 CoreFoundation 0x03457ac3 CFRunLoopRunSpecific + 467
14 CoreFoundation 0x034578db CFRunLoopRunInMode + 123
15 GraphicsServices 0x046949e2 GSEventRunModal + 192
16 GraphicsServices 0x04694809 GSEventRun + 104
17 UIKit 0x010bbd3b UIApplicationMain + 1225
18 ExampleApp 0x0011679d main + 125
19 libdyld.dylib 0x0300a701 start + 1)libc++abi.dylib: terminating with uncaught exception of type NSException
You can add a breakpoint to stop on all exceptions.
From Apple Docs
In the bottom-left corner of the breakpoints navigator, click the Add button.
Choose Add Exception Breakpoint.
In the Exception pop-up menu, choose the type of exception on which you want execution to stop:
All. Stops on all exceptions.
Objective-C. Stops on Objective-C exceptions.
C++. Stops on C++ exceptions.
To stop on a particular C++ exception, specify the exception name.
Choose the phase of the exception handling process at which you want program execution to stop.
Click Done.
The crash is happening in your +[ReportGenerator prepareReportList:] method. Specifically, when attempting to add an object to an array.
Only, the object is nil. Which is why the log starts with object cannot be nil.
(Note: As you come from the world of Java exceptions, don't make the mistake of thinking that ObjC exceptions are designed to be caught and recovered from. They aren't.)

Core data exception: initWithCoder:]: unrecognized selector sent

I'm experiencing this issue using Core Data.
CoreData: error: exception during fetchRowForObjectID: -[PharmaceuticalComp initWithCoder:]: unrecognized selector sent to instance 0x9ab1920 with userInfo of (null)
2014-08-18 07:56:55.784 HorizonMemory[1357:60b] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. -[PharmaceuticalComp initWithCoder:]: unrecognized selector sent to instance 0x9ab1920 with userInfo (null)
2014-08-18 07:56:55.786 HorizonMemory[1357:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[PharmaceuticalComp initWithCoder:]: unrecognized selector sent to instance 0x9ab1920'
*** First throw call stack:
(
0 CoreFoundation 0x021981e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x01f178e5 objc_exception_throw + 44
2 CoreFoundation 0x02235243 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x0218850b ___forwarding___ + 1019
4 CoreFoundation 0x021880ee _CF_forwarding_prep_0 + 14
5 Foundation 0x01b2a01a _decodeObjectBinary + 3498
6 Foundation 0x01b2b4d7 -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:] + 2204
7 Foundation 0x01b2b746 -[NSArray(NSArray) initWithCoder:] + 255
8 Foundation 0x01b2a01a _decodeObjectBinary + 3498
9 Foundation 0x01b2b4d7 -[NSKeyedUnarchiver _decodeArrayOfObjectsForKey:] + 2204
10 Foundation 0x01b37ff1 -[NSDictionary(NSDictionary) initWithCoder:] + 261
11 Foundation 0x01b2a01a _decodeObjectBinary + 3498
12 Foundation 0x01b29106 _decodeObject + 340
13 Foundation 0x01b28faa -[NSKeyedUnarchiver decodeObjectForKey:] + 181
14 Foundation 0x01b9aa86 +[NSKeyedUnarchiver unarchiveObjectWithData:] + 106
15 Foundation 0x01b197d5 -[_NSKeyedUnarchiveFromDataTransformer transformedValue:] + 47
16 CoreData 0x024205b9 _prepareResultsFromResultSet + 4105
17 CoreData 0x0241de33 newFetchedRowsForFetchPlan_MT + 1
PharmaComp is an NSManaged subclass linked to another entity User by a transient property -linkedPharma. User has this property in readonly mode. Every time I call linkedPharma it starts a fetch request that provides me the PharmaComp instance. When I try to delete User, i get this exception. the strange fact is that linkedPharma is a property not listed in the Model, thus PharmaComp shouldn't be involved in any sort of operation.The other fact is that it seems to try to use NSKeyedUnarchivier on it, but I don't understand why.
No object is hearing for NSManagedObjectContextObjectsDidChangeNotification.
I have no idea about where it came from.
The solution was pretty simple.
User had also another relationship with a transformable container (NSArray) which was holding (for a bug) a PharmaComp instance.

Firebase initWitURL crashes [FRepo initTransactions]: unrecognized selector

I have set up two similar firebase applications.
In both cases I call
self.firebase = [[Firebase alloc] initWithUrl:kFirebaseRoot];
in one case everything works fine.
In the other case I get a crash
2014-05-19 11:18:59.726 MyApp[28041:60b] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[FRepo initTransactions]: unrecognized selector sent to instance 0x8f50c10'
First throw call stack:*
0 CoreFoundation 0x023131e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x020928e5 objc_exception_throw + 44
2 CoreFoundation 0x023b0243 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x0230350b ___forwarding___ + 1019
4 CoreFoundation 0x023030ee _CF_forwarding_prep_0 + 14
5 MyApp 0x0002b63b -[FRepo initWithRepoInfo:] + 187
6 MyApp 0x0002ab05 -[FRepoManager getLocalRepo:] + 597
7 MyApp 0x0002b3ff +[FRepoManager getRepo:] + 111
8 MyApp 0x000544dc -[Firebase initWithUrl:] + 204
9 MyApp 0x000172f2 -[FLPresenceManager initFirebase] + 194
This appears to be something going on within Firebase, so I presume there must be something different in the way I have set up the app in the two cases. However, I cannot see a difference.
Can anyone offer any clues?
This answer was posted in the comments of the question.
The problem seems to be having -objC instead of -ObjC in the linker flags.
Just for completion sake for the next person, this is exactly where it can be found:

Can NSLayoutManager be safely used on background thread?

Even though the iOS doc says:
NLayoutManager, NSTextStorage, and NSTextContainer can be accessed
from subthreads as long as the app guarantees the access from a single
thread.
I encountered this exception occasionally:
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'Only run on the main
thread!'
Here is the backtrace:
Exception Type: SIGABRT
Exception Codes: #0 at 0x197bca58c
Crashed Thread: 7
Application Specific Information:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Only run on the main thread!'
Last Exception Backtrace:
0 CoreFoundation 0x000000018afd2f50 __exceptionPreprocess + 132
1 libobjc.A.dylib 0x00000001974dc1fc objc_exception_throw + 56
2 CoreFoundation 0x000000018afd2e10 +[NSException raise:format:arguments:] + 112
3 Foundation 0x000000018bb0ae20 -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 84
4 UIFoundation 0x00000001940f0654 -[NSLayoutManager(NSPrivate) _resizeTextViewForTextContainer:] + 412
5 UIFoundation 0x00000001940f0318 -[NSLayoutManager(NSPrivate) _recalculateUsageForTextContainerAtIndex:] + 1748
6 UIFoundation 0x000000019411ec2c _enableTextViewResizing + 236
7 UIFoundation 0x0000000194123e18 -[NSLayoutManager textContainerForGlyphAtIndex:effectiveRange:] + 484
8 UIFoundation 0x0000000194125c60 -[NSLayoutManager glyphRangeForTextContainer:] + 352
One thing to notice is that my NLayoutManager is attached to a UITextView. You can think it as a normal UITextView that is used to do text layout in background thread.
So does it mean that contradicting what the doc says, NLayoutManager can not be safely used on a single background thread if it is attached to a UITextView?
It seems to me that note in the docs actually explains the problem. Since you're using a layout manager attached to a UITextView, you can't guarantee it's being accessed from a single thread. It's best to assume that the text view could access the layout manager at any time, especially if the view is on screen. There's no way for you to know exactly how it's using the layout manager, but it's a safe bet that it's happening on the main thread.
You can have your background thread create a separate NSLayoutManager, NSTextStorage, and NSTextContainer, do all your layout calculations, and then apply those calculations on the main thread.

Resources