Im trying to create an infinite scroll type thing with Instagram using UITableView and AFNetworking however I get this error when I get to the bottom of the View:
CRASH :
-[__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object
2014-01-05 20:51:41.627 Floadt[1579:70b] STACK TRACE :
(
0 CoreFoundation 0x02b775e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x027a38b6 objc_exception_throw + 44
2 CoreFoundation 0x02b773bb +[NSException raise:format:] + 139
3 CoreFoundation 0x02bfe365 -[__NSCFArray insertObject:atIndex:] + 101
4 CoreFoundation 0x02b3b2d0 -[NSMutableArray insertObjects:count:atIndex:] + 208
5 CoreFoundation 0x02b3af69 -[NSMutableArray insertObjectsFromArray:range:atIndex:] + 425
6 CoreFoundation 0x02b3ad15 -[NSMutableArray addObjectsFromArray:] + 661
7 Floadt 0x0003f5ec __42-[StreamViewController nextInstagramPage:]_block_invoke + 284
8 Floadt 0x0001edfb __64-[AFJSONRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke91 + 43
9 libdispatch.dylib 0x035247f8 _dispatch_call_block_and_release + 15
10 libdispatch.dylib 0x035394b0 _dispatch_client_callout + 14
11 libdispatch.dylib 0x0352775e _dispatch_main_queue_callback_4CF + 340
12 CoreFoundation 0x02bdca5e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
13 CoreFoundation 0x02b1d6bb __CFRunLoopRun + 1963
14 CoreFoundation 0x02b1cac3 CFRunLoopRunSpecific + 467
15 CoreFoundation 0x02b1c8db CFRunLoopRunInMode + 123
16 GraphicsServices 0x0453c9e2 GSEventRunModal + 192
17 GraphicsServices 0x0453c809 GSEventRun + 104
18 UIKit 0x01936d3b UIApplicationMain + 1225
19 Floadt 0x0006646d main + 141
20 libdyld.dylib 0x037cb70d start + 1
21 ??? 0x00000001 0x0 + 1
)
Here is how I am making my code, what confuses me is the fact that all my Arrays are Mutable but it states that the mutating method was sent to an immutable object:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView
{
if (scrollView.contentOffset.y == roundf(scrollView.contentSize.height-scrollView.frame.size.height)) {
NSDictionary *page = instagramResponse[#"pagination"];
NSString *nextPage = page[#"next_url"];
[[InstagramClient sharedClient] getPath:[NSString stringWithFormat:#"%#",nextPage] parameters:nil success:^(AFHTTPRequestOperation *operation, id responseObject) {
instagramResponse = [responseObject mutableCopy];
[instagramResponse addEntriesFromDictionary:responseObject];
[instaPics addObjectsFromArray:responseObject[#"data"]];
[self.tableView reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Failure: %#", error);
}];
}
}
before addEntriesFromDictionary the copy of Dictionarylike this
NSDictionary *copyOfDic = [[NSDictionary alloc] initWithDictionary: originalDic copyItems: YES];
if (copyOfDic ) {
[destination addEntriesFromDictionary: copyOfDic ];
[copyOfDic release];
}
or
[instaPics addObjectsFromArray:[responseObject[#"data"]mutable copy]];
or
Your #property yourarray is either initialized with an NSArray or declared copy.
because both would be lead to this error/exception message since the backing ivar would point to an (immutable) NSArray.
If you have declared your property to be of NSMutableArray type, use strong as the storage modifier instead of copy.
Related
I'm looking into a somewhat frequent crash reported in my application's Crashlytics console.
One of the many examples I have has the following crashed thread stacktrace:
#11. Crashed: com.apple.root.default-qos
0 libobjc.A.dylib 0x22f3fa86 objc_msgSend + 5
1 Foundation 0x23ee3005 -[NSString caseInsensitiveCompare:] + 28
2 Foundation 0x23ed10bd _NSCompareObject + 28
3 Foundation 0x23ed109d _NSSortFunctionOne + 120
4 CoreFoundation 0x2373e6a3 __CFSimpleMergeSort + 114
5 CoreFoundation 0x2373e6c5 __CFSimpleMergeSort + 148
6 CoreFoundation 0x2373e6d9 __CFSimpleMergeSort + 168
7 CoreFoundation 0x2373e6c5 __CFSimpleMergeSort + 148
8 CoreFoundation 0x2373e6d9 __CFSimpleMergeSort + 168
9 CoreFoundation 0x2368ac35 CFSortIndexes + 404
10 CoreFoundation 0x2368c241 CFMergeSortArray + 176
11 Foundation 0x23ed0a9d _sortedObjectsUsingDescriptors + 456
12 Foundation 0x23f9c9fb -[NSSet(NSKeyValueSorting) sortedArrayUsingDescriptors:] + 510
13 MyApp 0x6d431 __24-[MyApp refresh]_block_invoke (MyApp.m:247)
14 CoreFoundation 0x23769499 __NSArrayEnumerate + 372
15 CoreFoundation 0x236e6c3b -[NSArray enumerateObjectsWithOptions:usingBlock:] + 62
16 MyApp 0x6d17d -[MyApp refresh] (MyApp.m:263)
17 MyApp 0xa97eb __52-[MyAppRequest updateAfterNotification:]_block_invoke (MyAppRequest.m:1175)
18 libdispatch.dylib 0x23307cbf _dispatch_call_block_and_release + 10
19 libdispatch.dylib 0x233136a1 _dispatch_root_queue_drain + 1572
20 libdispatch.dylib 0x2331307b _dispatch_worker_thread3 + 94
21 libsystem_pthread.dylib 0x234a6e0d _pthread_wqthread + 1024
22 libsystem_pthread.dylib 0x234a69fc start_wqthread + 8
Other instances of the crash occur in the same app code (in the refresh method of MyApp class), but during different parts of the CoreFoundation sortedArrayUsingDescriptors method logic. For example, another crash example stacktrace has:
0 libobjc.A.dylib 0x1823cdb90 objc_msgSend + 16
1 CoreFoundation 0x182c42738 CFStringCompareWithOptionsAndLocale + 232
2 Foundation 0x183644840 _NSCompareObject + 64
3 CoreFoundation 0x182d150f4 __CFSimpleMergeSort + 196
4 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
5 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
6 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
7 CoreFoundation 0x182d1513c __CFSimpleMergeSort + 268
8 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
9 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
10 CoreFoundation 0x182d15124 __CFSimpleMergeSort + 244
11 CoreFoundation 0x182c3b738 CFSortIndexes + 472
12 CoreFoundation 0x182c3cf58 CFMergeSortArray + 220
13 Foundation 0x1836440f8 _sortedObjectsUsingDescriptors + 564
14 Foundation 0x183725120 -[NSSet(NSKeyValueSorting) sortedArrayUsingDescriptors:] + 564
15 MyApp 0x10006f264 __24-[MyApp refresh]_block_invoke (MyApp.m:247)
The app code in refresh is:
- (void)refresh {
NSArray *products = [self getProducts];
NSMutableArray *validProducts = [NSMutableArray array];
[products enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
Product *prod = obj;
// Convert to internal native format (MyAppProduct) for business reasons...
MyAppProduct *myAppProd = [[MyAppProduct alloc] init];
myAppProd.ID = prod.id;
myAppProd.name = prod.name;
NSArray *subProds = [prod.subProds sortedArrayUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"subProds" ascending:NO]]];
NSMutableArray *validSubProds = [NSMutableArray array];
[subProds enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
SubProd *subProd = obj;
// Convert to internal native format (MyAppSubProduct) for business reasons...
MyAppSubProduct *myAppSubProd = [[MyAppSubProduct alloc] initWithSubProd:subProd];
[validSubProds addObject:myAppSubProd];
}];
myAppProd.subProds = validSubProds;
myAppProd.count = [product.count integerValue];
// Add to array
[validProducts addObject:myAppProd];
}];
// Apply array to self
_products = validProducts
}
where getProducts is:
- (NSArray*)getProducts {
NSFetchRequest *productFetchRequest = [NSFetchRequest fetchRequestWithEntityName:#"Products"];
// Filter
NSMutableArray *productsPredicates = [NSMutableArray array];
[productsPredicates addObject:[NSPredicate predicateWithFormat:#"life_uid == %#", req.lifeUid]];
[productsPredicates addObject:[NSPredicate predicateWithFormat:#"hidden == %#", #NO]];
[productFetchRequest setPredicate:[NSCompoundPredicate andPredicateWithSubpredicates:productsPredicates]];
// Sort
NSSortDescriptor *sortProductsByName = [NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES];
[productFetchRequest setSortDescriptors:#[sortProductsByName]];
[productFetchRequest setReturnsObjectsAsFaults:NO];
[productFetchRequest setRelationshipKeyPathsForPrefetching:#[#"subprods", #"subprods.special"]];
NSManagedObjectContext *moc = [MyAppCoreDataController sharedController].mainManagedObjectContext;
NSError *error = nil;
NSArray *products = [moc executeFetchRequest:productFetchRequest error:&error];
if (error) {
NSLog(#"Error fetching products %#", error);
}
return products;
}
And refresh is being called like so:
- (void)updateAfterNotification:(NSNotification *)notification {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[MyApp instance] refresh];
});
}
Most likely it's because you're not handling Core Data concurrency correctly. When you create a managed object context using NSPrivateQueueConcurrencyType or NSMainQueueConcurrencyType, you must put all Core Data access inside a call to performBlock or performBlockAndWait. That includes fetches as well as accessing attribute values of fetched objects.
You're using dispatch_async, which is not the right way to handle concurrency with Core Data. You should switch to using performBlock or performBlockAndWait.
I am trying to add object to the array from a dictionary . In else part I am getting this error
mutating method sent to immutable object'
NSMutableDictionary *selectedDict = [NSMutableDictionary new];
[selectedDict setObject:editedLineItem forKey:#"Text"];
[selectedDict setObject:#"fa-check" forKey:#"IconClass"];
NSMutableArray *tagListDictionary = [NSMutableArray new];
[tagListDictionary addObject:selectedTagsArray];
LineItemsStorage *linestorage = [LineItemsStorage sharedManager];
if(![linestorage.packagesArray valueForKey:#"Id"])
{
[linestorage.selectedLineItemsAndTagsArray addObject:selectedDict];
}
else{ [[linestorage.packagesArray valueForKey:#"LineItems"]addObject:[NSMutableArray arrayWithObject:selectedDict]];
}
-[NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'
*** First throw call stack:
(
0 CoreFoundation 0x00000001154a1d85 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000114f15deb objc_exception_throw + 48
2 CoreFoundation 0x00000001154a1cbd +[NSException raise:format:] + 205
3 CoreFoundation 0x0000000115497b0a -[__NSCFArray insertObject:atIndex:] + 106
4 FlatPebble 0x000000010f276014 -[LineItemViewController okayAction] + 836
5 UIKit 0x0000000113809a8d -[UIApplication sendAction:to:from:forEvent:] + 92
6 UIKit 0x000000011397ce67 -[UIControl sendAction:to:forEvent:] + 67
7 UIKit 0x000000011397d143 -[UIControl _sendActionsForEvents:withEvent:] + 327
8 UIKit 0x000000011397c263 -[UIControl touchesEnded:withEvent:] + 601
9 UIKit 0x000000011387c99f -[UIWindow _sendTouchesForEvent:] + 835
10 UIKit 0x000000011387d6d4 -[UIWindow sendEvent:] + 865
11 UIKit 0x0000000113828dc6 -[UIApplication sendEvent:] + 263
12 UIKit 0x0000000113802553 _UIApplicationHandleEventQueue + 6660
13 CoreFoundation 0x00000001153c7301 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
14 CoreFoundation 0x00000001153bd22c __CFRunLoopDoSources0 + 556
15 CoreFoundation 0x00000001153bc6e3 __CFRunLoopRun + 867
16 CoreFoundation 0x00000001153bc0f8 CFRunLoopRunSpecific + 488
17 GraphicsServices 0x0000000116e5cad2 GSEventRunModal + 161
18 UIKit 0x0000000113807f09 UIApplicationMain + 171
19 *********** 0x000000010f348c2f main + 111
20 libdyld.dylib 0x0000000115d9992d start + 1
)
Use this code
NSMutableDictionary *selectedDict = [[NSMutableDictionary new]mutableCopy];
[selectedDict setObject:editedLineItem forKey:#"Text"];
[selectedDict setObject:#"fa-check" forKey:#"IconClass"];
NSMutableArray *tagListDictionary = [[NSMutableArray new]mutableCopy];
[tagListDictionary addObject:selectedTagsArray];
LineItemsStorage *linestorage = [LineItemsStorage sharedManager];
if(![linestorage.packagesArray valueForKey:#"Id"])
{
[linestorage.selectedLineItemsAndTagsArray addObject:selectedDict];
}
else{ [[linestorage.packagesArray valueForKey:#"LineItems"]addObject:[NSMutableArray arrayWithObject:selectedDict]];
}
Assuming your packagesArray contains an array containing one or more objects that have a LineItems property (that happens to also be an array); your problem is here:
[[linestorage.packagesArray valueForKey:#"LineItems"]addObject:[NSMutableArray arrayWithObject:selectedDict]]
Breaking it down it is equivalent to:
NSArray* packagesLineItems = [linestorage.packagesArray valueForKey:#"LineItems"];
NSMutableArray* selected = [NSMutableArray arrayWithObject:selectedDict];
[packagesLineItems addObject:selected];
So your problem is either the return type of valueForKey (when called on an array), or the action you're trying to do on it.
For the below code snippet:
error occurs at setObject: forKey:
response <--is an NSDictionary
if(response){
NSMutableArray *lifeArray = [[NSMutableArray alloc] init];
NSMutableDictionary *responseDict = [[NSMutableDictionary alloc] init];
responseDict = (NSMutableDictionary *)[response mutableCopy];
[responseDict setObject:#"life" forKey:#"label"]; <-- Error here
}
Note that variable responseDict is NSMutableDictionary since copied via mutableCopy.
Error message:
2014-11-12 12:16:08.534 Lifetape[84381:508759] -[__NSCFArray setObject:forKey:]: unrecognized selector sent to instance 0x7a296700
2014-11-12 12:16:08.536 Lifetape[84381:508759] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFArray setObject:forKey:]: unrecognized selector sent to instance 0x7a296700'
*** First throw call stack:
(
0 CoreFoundation 0x028fbdf6 __exceptionPreprocess + 182
1 libobjc.A.dylib 0x02557a97 objc_exception_throw + 44
2 CoreFoundation 0x02903a75 -[NSObject(NSObject) doesNotRecognizeSelector:] + 277
3 CoreFoundation 0x0284c9c7 ___forwarding___ + 1047
4 CoreFoundation 0x0284c58e _CF_forwarding_prep_0 + 14
5 Lifetape 0x000dfb83 __50-[LTTimeLineTableViewController getTimeIntervals:]_block_invoke + 307
6 Lifetape 0x0014cedb -[MethodInvoker maybeInvokeCallback] + 395
7 Lifetape 0x0014d19f -[MethodInvoker receiveResultWithError:andResult:] + 399
8 Lifetape 0x00143e38 -[MeteorClient(Connection) livedata_result:] + 1544
9 Lifetape 0x00138674 __54-[MeteorClient(Connection) initConnectionWithOptions:]_block_invoke_3 + 2660
10 Lifetape 0x0014b2b5 -[MeteorClient didReceiveMessage:] + 197
11 Lifetape 0x0014eb7d -[ObjectiveDDP webSocket:didReceiveMessage:] + 269
12 Lifetape 0x0015d986 __30-[SRWebSocket _handleMessage:]_block_invoke + 102
13 libdispatch.dylib 0x031e941a _dispatch_call_block_and_release + 15
14 libdispatch.dylib 0x03209e1f _dispatch_client_callout + 14
15 libdispatch.dylib 0x031f0981 _dispatch_main_queue_callback_4CF + 610
16 CoreFoundation 0x02855f3e __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 14
17 CoreFoundation 0x02814d40 __CFRunLoopRun + 2256
18 CoreFoundation 0x028141ab CFRunLoopRunSpecific + 443
19 CoreFoundation 0x02813fdb CFRunLoopRunInMode + 123
20 GraphicsServices 0x051a524f GSEventRunModal + 192
21 GraphicsServices 0x051a508c GSEventRun + 104
22 UIKit 0x00f41e16 UIApplicationMain + 1526
23 Lifetape 0x000ce36d main + 141
24 libdyld.dylib 0x03235ac9 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Here your response dictionary is a NSDictionary type collection so it does not have any selector like setObject, that's why it is giving you this error use
if(response && [response isKindOfClass:[NSDictionary class]]){
NSMutableArray *lifeArray = [[NSMutableArray alloc] init];
NSMutableDictionary *responseDict = [NSMutableDictionary dictionaryWithDictionary:response];
[responseDict setObject:#"life" forKey:#"label"];
}
and it will work but make sure response is your dictionary type object. as the error you have posted clearly says that your response is an array not a dictionary.
Your response looks like NSArray class so try below code.
if([response isKindOfClass:[NSArray Class]]){
NSLog(#"Array");
}
else if([response isKindOfClass:[NSDictionary Class]]){
NSLog(#"Dictionary");
}
Now manage your code as per log.
[self.kvoController observe:user keyPath: #"fullName" options:NSKeyValueObservingOptionNew block:^(id observer, id object, NSDictionary *change) {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *fullname = [change objectForKey:NSKeyValueChangeNewKey];
if ([fullname isKindOfClass:[NSString class]]) {
if (![weakSelf.fullnameLabel.text isEqualToString: fullname]) {
weakSelf.fullnameLabel.text = fullname;
[weakSelf.fullnameLabel sizeToFit];
}
}
});
}];
This code crashes on the 3rd line NSString *fullname = [change objectForKey:NSKeyValueChangeNewKey];
The crash log is as below:
Crashed: com.apple.main-thread EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0x00002069
0 libobjc.A.dylib 0x38449612 objc_retain + 17
1 Retro 0x0013336b __33-[ProfileHeaderView observeUser:]_block_invoke_2491 (ProfileHeaderView.m:598)
2 libdispatch.dylib 0x38922833 _dispatch_call_block_and_release + 10
3 libdispatch.dylib 0x3892281f _dispatch_client_callout + 22
4 libdispatch.dylib 0x3892949f _dispatch_main_queue_callback_4CF$VARIANT$mp + 278
5 CoreFoundation 0x2d83b8f1 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 8
6 CoreFoundation 0x2d83a1c5 __CFRunLoopRun + 1300
7 CoreFoundation 0x2d7a4f0f CFRunLoopRunSpecific + 522
8 CoreFoundation 0x2d7a4cf3 CFRunLoopRunInMode + 106
9 GraphicsServices 0x326ca663 GSEventRunModal + 138
10 UIKit 0x300f016d UIApplicationMain + 1136
11 Retro 0x0007d253 main (main.m:16)
Any idea why it crashed because I can't replicate this on my device (the log is from crash reporter).
I am getting this crash showing up in BugSense:
-[NSConcreteData count]: unrecognized selector sent to instance 0x14e57f10 - NSInvalidArgumentException
in this code:
+ (NSMutableArray *)applyFilters:(NSMutableArray *)theItems fromFilter:(NSDictionary *)filters
{
NSMutableArray *items = [[NSMutableArray alloc] initWithArray:theItems];
if ([[filters allKeys] count] > 0)
{
NSMutableArray *tempFilteredItems = [[NSMutableArray alloc] init];
for (NSString *key in [filters allKeys])
{
NSMutableString *convertedKey = [NSMutableString stringWithString:key];
[convertedKey replaceOccurrencesOfString:#" "
withString:#"_"
options:NSCaseInsensitiveSearch
range:NSMakeRange(0, [convertedKey length])];
NSArray *tempFilterAttributes = [NSArray arrayWithArray:filters[key]];
for (NSDictionary *item in items)
{
if (![[item[convertedKey] componentsSeparatedByString:#"*"] firstObjectCommonWithArray:tempFilterAttributes])
{
if (![tempFilteredItems containsObject:item])
{
[tempFilteredItems addObject:item];
}
}
}
[items removeObjectsInArray:tempFilteredItems];
[tempFilteredItems removeAllObjects];
}
}
return items;
}
Why/how is this happening?
Stack trace is:
CoreFoundation <redacted> + 130
1 libobjc.A.dylib objc_exception_throw + 38
2 CoreFoundation <redacted> + 202
3 CoreFoundation <redacted> + 706
4 CoreFoundation _CF_forwarding_prep_0 + 24
5 CoreFoundation <redacted> + 28
6 Video Games +[Helper applyFilters:fromFilter:] (Helper.m:2862)
7 Video Games -[WishlistViewController loadUp] (WishlistViewController.m:409) + 29303
8 Video Games -[WishlistViewController viewWillAppear:] (WishlistViewController.m:363) + 27955
9 UIKit <redacted> + 374
10 UIKit <redacted> + 612
11 UIKit <redacted> + 572
12 UIKit <redacted> + 44
13 UIKit <redacted> + 184
14 UIKit <redacted> + 380
15 QuartzCore <redacted> + 142
16 QuartzCore <redacted> + 350
17 QuartzCore <redacted> + 16
18 QuartzCore <redacted> + 228
19 QuartzCore <redacted> + 314
20 UIKit <redacted> + 126
21 CoreFoundation <redacted> + 20
22 CoreFoundation <redacted> + 286
23 CoreFoundation <redacted> + 738
24 CoreFoundation CFRunLoopRunSpecific + 524
25 CoreFoundation CFRunLoopRunInMode + 106
26 GraphicsServices GSEventRunModal + 138
27 UIKit UIApplicationMain + 1136
28 Video Games main (main.m:16) + 888911
29 libdyld.dylib <redacted> + 2
The problem has nothing to do with the code that you provided. The error messages says that the message count was sent to the class NSConcreteData, which is essentially the same as NSData, and such a class method does not exist.
I suggest that you set an exception breakpoint (in Xcode select left the breakpoint navigator, click + left bottom, and select add exception breakpoint).
When you execute the app, it will stop at the faulty instruction.
EDIT (due to the stack trace you provided now):
The stack trace indeed says that your method applyFilters:fromFilter: is responsible for the crash. The only place where the message count is sent in this method, is the statement [[filters allKeys] count]. It looks then that count is sent to an NSConcreteData object, and not to an NSArray object as you might have expected. One reason could be that the argument filters, that should be a NSDictionary, is an object of a different type.
So when the app stops at the exception breakpoint, please check the class of the instance filters.