1
votes

Can someone tell me why on the first past (or sometimes 5th pass through) this code works. However I am getting a crash at random with the following message:

__NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'

Here is the code:

if (![self.recentSearchesArray containsObject:self.filterParameters[@"includedKeywords"]]){

        [self.recentSearchesArray addObject:[self.filterParameters [@"includedKeywords"] mutableCopy]];
        [[NSUserDefaults standardUserDefaults]setObject:[self.recentSearchesArray mutableCopy] forKey:@"RecentSearches"];
        [self.SavedSearchesTableView reloadData];
    }

The recent search array is an NSMutableArray declared as a @property(strong, nonotomic)NSMutableArray *recentSearchesArray

It is crashing when I am adding an object to the array.

Edit

My recent searches array is allocated like so:

if (!self.recentSearchesArray){
        self.recentSearchesArray = [NSMutableArray array];
    }

My filtered parameters dictionary is allocated like so:

    self.filterParameters = [NSMutableDictionary dictionaryWithDictionary:params];

params is an NSDictionary allocated like so:

NSDictionary *params = [NSDictionary dictionaryWithObject:self.searchTerm forKey:@"includedKeywords"];

Solution

As per marked answer - NSUserDefaults was the issue:

self.recentSearchesArray = [[NSUserDefaults standardUserDefaults]objectForKey:@"RecentSearches"];

This returned a NSArray instead of NSMutableArray. I never thought that was the case with NSUserDefaults.

Here is the correct way to return a mutable copy

    self.recentSearchesArray = [[[NSUserDefaults standardUserDefaults]objectForKey:@"RecentSearches"] mutableCopy];
2
is your recentSearchesArray referring to mutable instance? - Rajesh
Yes - the dictionary is mutable. self.filteredParameters - Robert J. Clegg
Array or dictionary? How are you allocating it? - Rajesh
Edited the question to show allocations. - Robert J. Clegg

2 Answers

2
votes

Check where place where you're setting recentSearchArray variable. Maybe you're setting it to object of NSArray. Also check code where you're getting this array from NSUserDefaults, because NSUserDefaults will return object of class NSArray.

0
votes

I had a very similar issue with NSMutableDictionary on iOS12. I could create an NSMutableDictionary using dictionaryWithCapacity, but if I recalled one using

[[NSMutableDictionary alloc] initWithContentsOfURL: [self urlForUnsentFilesDictionary] error:&writeError];

when I later tried to add an object to it I would get that error. Worked fine on iOS13. I ended up fixing it by adding this after the initWithContentsOfURL:

dict = CFBridgingRelease( CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (__bridge CFDictionaryRef)dict, kCFPropertyListMutableContainersAndLeaves) );

Hope this helps someone!