Create a new NsmutableArray in ios - ios

Hello I am newbie to ios and objective c. I am working on a demo. In that I am having a for loop for adding values to NSMutableArray. Now this array will be added to NSMutableDictionary. Now inside this for loop i am having an if condition for checking string. I am adding objects to the array in "if" part and want to create a new Array when condition fail. I have tried as below, but in my Dictionary only one array saved. Can anyone help me where i have made mistake?
NSMutableArray *listingCommonArr,sectionTitles,eventDate;
int j=0;
NSString *dt;
NSMutableArray *sectionArray = [[NSMutableArray alloc]init];
sectionTitles = [orderedSet array];
NSLog(#"===listing common array---%d",[listingCommonArr count]);
sectionData = [[NSMutableDictionary alloc]init];
for(int i =0;i<[listingCommonArr count];i++)
{
dt = [[listingCommonArr objectAtIndex:i] objectForKey:#"start_date"];
NSLog(#"====my date at place===%# & my date is====%#",[sectionTitles objectAtIndex:j],dt);
for (int i =0; i < [listingCommonArr count]; i++) {
dt = [[listingCommonArr objectAtIndex:i] objectForKey:#"start_date"];
if ([(NSString *)[sectionTitles objectAtIndex:j] isEqualToString:dt]) {
[sectionArray addObject:listingCommonArr[i]];
//sectionData = #{dt : sectionArray}; // <-- PAY ATTENTION ON THIS LINE, PLEASE
//[sectionData setValue:sectionArray forKey:dt];
sectionData = [#{dt : sectionArray} mutableCopy];
} else {
[sectionData setObject:#"New value" forKey:#"string"];
sectionArray = [[NSMutableArray alloc]init];
j++;
}
}
NSLog(#"====my section DAta is==%#",sectionData);
}
errorTrace
-[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0x7fc6547832a0
2015-12-18 19:39:41.387 iPhoneExploreCayman[41719:13822557] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance 0x7fc6547832a0'
*** First throw call stack:
(
0 CoreFoundation 0x000000010a551c65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010a1e8bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010a5590ad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x000000010a4af13c ___forwarding___ + 988
4 CoreFoundation 0x000000010a4aecd8 _CF_forwarding_prep_0 + 120
5 iPhoneExploreCayman 0x000000010604a48c -[iPhoneECListingView GetEventListingData:] + 1884
6 iPhoneExploreCayman 0x000000010605644b -[iPhoneECListingView EventListStart] + 1323
7 iPhoneExploreCayman 0x0000000106055a98 -[iPhoneECListingView EventClicked:] + 2312
8 UIKit 0x0000000108832d62 -[UIApplication sendAction:to:from:forEvent:] + 75
9 UIKit 0x000000010894450a -[UIControl _sendActionsForEvents:withEvent:] + 467
10 UIKit 0x00000001089438d9 -[UIControl touchesEnded:withEvent:] + 522
11 UIKit 0x000000010887f958 -[UIWindow _sendTouchesForEvent:] + 735
12 UIKit 0x0000000108880282 -[UIWindow sendEvent:] + 682
13 UIKit 0x0000000108846541 -[UIApplication sendEvent:] + 246

I'm highly confused about what you actually want to do here, but... after your comments I have completely updated my answer removing the previous assumptions about what actually is supposed to happen.
it seems to me you want(ed) to group a series of words by the first letter. you have posted a list of animals as example, so I worked with those.
you defined the expected output:
NSDictionary *_expectedOutput = #{#"A" :#[#"Affrican cat", #"Assian cat", #"Alsesian fox"], #"B" : #[#"Bear", #"Black Swan", #"Buffalo"], #"C" : #[#"Camel", #"Cockatoo"], #"D" : #[#"Dog", #"Donkey"], #"E" : #[#"Emu"], #"R" : #[#"Rhinoceros"], #"S" : #[#"Seagull"], #"T" : #[#"Tasmania Devil"], #"W" : #[#"Whale", #"Whale Shark", #"Wombat"]};
as you can see my input array is just an unsorted list of random names of animals from your sample output:
NSArray *_input = #[#"Whale Shark", #"Tasmania Devil", #"Affrican cat", #"Bear", #"Seagull", #"Black Swan", #"Whale", #"Wombat", #"Camel", #"Rhinoceros", #"Cockatoo", #"Buffalo", #"Assian cat", #"Alsesian fox", #"Emu"];
I'm working with that input array and I am going to group them by their first letter and build up the output:
NSMutableDictionary *_output = [NSMutableDictionary dictionary];
[[_input sortedArrayUsingSelector:#selector(compare:)] enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
NSString *_firstLetter = (obj.length > 0 ? [obj substringToIndex:1] : nil);
if (_firstLetter) {
NSMutableArray *_list = [_output valueForKey:_firstLetter];
if (_list == nil) {
_list = [NSMutableArray arrayWithObject:obj];
[_output setValue:_list forKey:_firstLetter];
} else {
[_list addObject:obj];
}
}
}];
that is pretty much it, if you'd log the _output, you can see on the console that is identical to your _expectedOutput collection.

you have sectionData = #{dt : sectionArray}; outside of the if section.
So on each iteration you dictionary will be recreated.
As I think you need the Mutable dictionary for sectionData, and move that string under "else" section
1 initialize mutable dictionary somewhere before the loop:
sectionData = [NSMutableDictionary new];
2 adding current array to dictionary must be under "else" block, also as I understand, you should create new sectionArray:
else
{
[sectionData setObject: sectionArray forKey:dt];
sectionArray = [[NSMutableArray alloc]init];
}

Every time you call sectionData = #{dt : sectionArray}; or anything sectionData is set other values are remove from dictionary and only last pair stays.(you are initializing dictionary every time you call setObject: forKey:)
If you want to create mutable dictionary and add objects to it you should do:
NSMutableDictionary *d2 = [NSMutableDictionary new];//sectionData in your case
[d2 addEntriesFromDictionary:#{#"b":#"c"}];//new key value pair added to d2
[d2 addEntriesFromDictionary:#{#"c":#"d"}];//new key value pair added to d2
[d2 addEntriesFromDictionary:#{#"d":#"e"}];//new key value pair added to d2

Related

Firebase remote config crashing (objective c iOS)

I am having trouble fetching information from Firebase RemoteConfig. On app install, I have a language selection screen before the MainController view controller. On the MainController View controller, I am doing a RemoteConfig fetch. It works the first time, when the language selection screen is shown before the MainController view controller. But, from the next time, it crashes on this particular line:
[self.remoteConfig fetchWithExpirationDuration:expirationDuration completionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) {
With the following exception:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTaggedPointerString firstObject]: unrecognized selector sent to instance 0xa0000000000616a2'
*** First throw call stack:
(
0 CoreFoundation 0x000000010d20134b __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010cc6221e objc_exception_throw + 48
2 CoreFoundation 0x000000010d270f34 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132
3 CoreFoundation 0x000000010d186c15 ___forwarding___ + 1013
4 CoreFoundation 0x000000010d186798 _CF_forwarding_prep_0 + 120
5 English 0x0000000107f44e1b -[GIPLocale googleLanguageWithAppleLanguages:] + 33
6 English 0x0000000107f45396 -[GIPLocale recalculateLocale] + 54
7 English 0x0000000107f44c26 -[GIPLocale initWithLanguageMappings:] + 99
8 English 0x0000000107f44b77 __25+[GIPLocale googleLocale]_block_invoke + 41
9 libdispatch.dylib 0x000000010da900cd _dispatch_client_callout + 8
10 libdispatch.dylib 0x000000010da751fc dispatch_once_f + 501
11 English 0x0000000107f44b4c +[GIPLocale googleLocale] + 42
12 English 0x0000000107f42d06 +[RCNDevice deviceLocale] + 31
13 English 0x0000000107f43344 +[RCNDevice hasDeviceContextChanged:projectIdentifier:] + 325
14 English 0x0000000107f3e133 -[RCNConfigFetch fetchAllConfigsWithExpirationDuration:completionHandler:] + 150
15 English 0x0000000107f3577f -[FIRRemoteConfig fetchWithExpirationDuration:completionHandler:] + 77
UPDATE: It doesn't matter if I show the language selection screen or not. It always works on a fresh install and stops working from next launches.
This is my full code I am using.
-(void)viewDidAppear:(BOOL)animated{
//Display select language settings
if (![[NSUserDefaults standardUserDefaults] boolForKey:DISPLAY_LANGUAGE_SETTING])
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:TRUE forKey:DISPLAY_LANGUAGE_SETTING];
[defaults synchronize];
//Display Language Screen
AGSelectLanguageViewController *languageViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"AGSelectLanguageViewController"];
self.modalPresentationStyle = UIModalPresentationFullScreen;
[self presentViewController:languageViewController animated:NO completion:nil];
}
[self configFireBase];
}
-(void)configFireBase{
// Firebase Configuration
self.remoteConfig = [FIRRemoteConfig remoteConfig];
//Enabling development mode
FIRRemoteConfigSettings *remoteConfigSettings = [[FIRRemoteConfigSettings alloc] initWithDeveloperModeEnabled:YES];
self.remoteConfig.configSettings = remoteConfigSettings;
//Set default Remote Config values
[self.remoteConfig setDefaultsFromPlistFileName:#"RemoteConfigDefaults"];
[self fetchConfig];
}
- (void)fetchConfig {
_discount_percentage = self.remoteConfig[DISCOUNT_PERCENTAGE].numberValue.floatValue;
long expirationDuration = 3600;
if (self.remoteConfig.configSettings.isDeveloperModeEnabled) {
expirationDuration = 0;
}
[self.remoteConfig fetchWithExpirationDuration:expirationDuration completionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) {
if (status == FIRRemoteConfigFetchStatusSuccess) {
NSLog(#"Config fetched!");
[self.remoteConfig activateFetched];
} else {
NSLog(#"Config not fetched");
NSLog(#"Error %#", error.localizedDescription);
}
}];
}
Where am I wrong? Please help.
The GIPLocale class does some mapping between Google and Apple names for locales, and as part of that it pulls the app's locales from NSUserDefaults:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSArray *languages = [defaults objectForKey:#"AppleLanguages"];
I am guessing that somewhere that defaults entry is getting set to just a string or similar rather than an array - check if you're referencing that string anywhere in your app.

App crashes at [__NSCFDictionary setObject:forKey:] in iOS 9 only

While validating for null values ,the crashes with
-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
When I am using all mutable type.(crashing only in iOS 9,other versions of my app in Appstore are working fine)
Can anyone suggest me how to handle this at null condition to setValue for key.
NSMutableArray *tempelementsArray=[[NSMutableArray alloc]init];
if(![[catDic objectForKey:#"menuElementList"] isEqual:#""]){
tempelementsArray = [catDic objectForKey:#"menuElementList"];
if(tempelementsArray != nil && [tempelementsArray count]>0)
{
for (NSInteger j=0; j<tempelementsArray.count; j++) {
NSMutableDictionary *elementDic = [[NSMutableDictionary alloc]init];
elementDic = [tempelementsArray objectAtIndex:j];
[elementDic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if ([obj isKindOfClass:[NSNull class]])
{
[elementDic setValue:#"" forKey:key];//App crashes here when one of the value is NULL
}
} ];
}
with below crash:
*** Terminating app due to uncaught exception NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
*** First throw call stack:
(
0 CoreFoundation 0x00df3a94 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x0051be02 objc_exception_throw + 50
2 CoreFoundation 0x00df39bd +[NSException raise:format:] + 141
3 CoreFoundation 0x00d0ed68 -[__NSCFDictionary setObject:forKey:] + 104
4 Foundation 0x001051ba -[NSMutableDictionary(NSKeyValueCoding) setValue:forKey:] + 68
5 coreDataMenuSample 0x000481d9 __33-[ViewController SaveToCoredata:]_block_invoke188 + 217
6 CoreFoundation 0x00df2849 ____NSDictionaryEnumerate_block_invoke417 + 41
7 CoreFoundation 0x00cd5452 CFBasicHashApply + 130
8 CoreFoundation 0x00d12481 __NSDictionaryEnumerate + 273
9 CoreFoundation 0x00d122ed -[NSDictionary enumerateKeysAndObjectsWithOptions:usingBlock:] + 45
10 CoreFoundation 0x00d12235 -[NSDictionary enumerateKeysAndObjectsUsingBlock:] + 53
11 coreDataMenuSample 0x00043e71 -[ViewController SaveToCoredata:] + 6481
12 coreDataMenuSample 0x0004239d -[ViewController viewDidLoad] + 893
13 UIKit 0x0133fd74 -[UIViewController _sendViewDidLoadWithAppearanceProxyObjectTaggingEnabled] + 44
14 UIKit 0x013448c2 -[UIViewController loadViewIfRequired] + 1556
)
libc++abi.dylib: terminating with uncaught exception of type NSException
I have even checked this similar issue Strange “mutating method sent to immutable object” error when adding an object to a mutable array
Saving CLLocation error: Mutating method sent to immutable object
Look at your code, I think the problem is this line
NSMutableDictionary *elementDic = [[NSMutableDictionary alloc]init];
elementDic = [tempelementsArray objectAtIndex:j];
tempelementsArray contains an instance of NSDictionary instead of NSMutableDictionary. Change to this code will help:
NSMutableDictionary *elementDic = [[NSMutableDictionary alloc]initWithDictionary:tempelementsArray[j]];
There are several things wrong with your code :
First it's not because you initialise a variable with a mutable object that subsequent initialisations will be converted to mutable objects. So when you do :
NSMutableDictionary *elementDic = [[NSMutableDictionary alloc]init];
elementDic = [tempelementsArray objectAtIndex:j];
elementDic contains whatever was in the array at index j, so in this case probably an immutable object. You have to make mutable copies of your objects if you want them mutable.
Second, you can't mutate a dictionary while you enumerate it (which is what you are trying to do here). You have to make a mutable copy and mutate the copy while you enumerate the original.
Third, if you expect [catDic objectForKey:#"menuElementList"] to be an array, why do you test if it's equal to an empty string ?!
Here is a fixed version of your code (with modern obj-C syntax which is much easier to read by the way)
NSDictionary *catDic = ...
NSArray *tempElementsArray = catDic[#"menuElementList"];
NSMutableArray *mutableTempElementsArray = [NSMutableArray arrayWithCapacity:tempElementsArray.count];
if (![tempElementsArray isEqual:#""] && tempElementsArray != nil && tempElementsArray.count > 0)
{
for (NSUInteger j = 0; j < tempElementsArray.count; j++)
{
NSDictionary *elementsDic = tempElementsArray[j];
NSMutableDictionary *mutableElementsDic = [NSMutableDictionary dictionaryWithCapacity:elementsDic.count];
[elementsDic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
if (obj == [NSNull null]) {
obj = #"";
}
mutableElementsDic[key] = obj;
}];
[mutableTempElementsArray addObject:mutableElementsDic];
}
}
NSMutableDictionary *mutableCatDic = [NSMutableDictionary dictionaryWithDictionary:catDic];
mutableCatDic[#"menuElementList"] = mutableTempElementsArray;

iOS Crash Log NSObject doesNotRecognizeSelector: - at which line?

I have recorded a crash of my app, but the last line in my app (5 Control) points just to the method begin. How do I know in which line the problem is?
0 CoreFoundation 0x185f0af50 __exceptionPreprocess + 132
1 libobjc.A.dylib 0x1924141fc objc_exception_throw + 60
2 CoreFoundation 0x185f0fc04 -[NSObject(NSObject) doesNotRecognizeSelector:] + 220
3 CoreFoundation 0x185f0d930 ___forwarding___ + 912
4 CoreFoundation 0x185e2d5dc _CF_forwarding_prep_0 + 92
5 Control 0x10005acb4 -[PaymillPaymentService handleTransactionListRequest:] (PaymillPaymentService.m:211)
6 Foundation 0x186a7416c __103+[__NSOperationInternal _observeValueForKeyPath:ofObject:changeKind:oldValue:newValue:indexes:context:]_block_invoke96 + 28
7 libdispatch.dylib 0x1929ec014 _dispatch_call_block_and_release + 24
8 libdispatch.dylib 0x1929ebfd4 _dispatch_client_callout + 16
9 libdispatch.dylib 0x1929f32b8 _dispatch_root_queue_drain + 556
10 libdispatch.dylib 0x1929f34fc _dispatch_worker_thread2 + 76
11 libsystem_pthread.dylib 0x192b816bc _pthread_wqthread + 356
12 libsystem_pthread.dylib 0x192b8154c start_wqthread + 4
Here the [lengthy] method code. I see a couple of places where I can add the check but how to I know it for sure that I fixed the issue? The problem is sporadical and I cannot reproduce it easily.
- (void)handleTransactionListRequest:(ServiceRequest *)serviceRequest
{
LRURLRequestOperation* operation = serviceRequest.operation;
NSHTTPURLResponse *response = (NSHTTPURLResponse *)operation.URLResponse;
if (response.statusCode == 200)
{
if (operation.responseData)
{
NSError *parserError = nil;
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:operation.responseData options:0 error:&parserError];
//NSLog(#"%#", data);
if (!parserError)
{
NSArray* transactions = [data objectForKey:#"data"];
if (0 == serviceRequest.currentOffset)
{
NSNumber* totalCountObj = [data objectForKey:#"data_count"];
serviceRequest.totalCount = [totalCountObj intValue];
}
int loadedCount = 0;
if (transactions)
{
for (id object in transactions)
{
TransactionInfo* info = [self createTransactionFrom:object];
[serviceRequest.transactionList addTransaction:info];
[info release];
loadedCount++;
}
}
if (loadedCount + serviceRequest.currentOffset >= serviceRequest.totalCount)
{
if ([serviceRequest.delegate respondsToSelector:#selector(transactionListLoadingComplete:)])
[serviceRequest.delegate transactionListLoadingComplete:serviceRequest];
serviceRequest.transactionList.timeStamp = [[NSDate date] timeIntervalSince1970];
NSLog(#"COMPLETE: %d transaction loaded ", serviceRequest.totalCount);
}
else
{
serviceRequest.currentOffset += loadedCount;
bool needToContinue = YES;
if ([serviceRequest.delegate respondsToSelector:#selector(transactionListLoadingContinue:)])
needToContinue = [serviceRequest.delegate transactionListLoadingContinue];
if (needToContinue)
{
[self continueRetrievingTransactionListFor:serviceRequest];
NSLog(#"CONTINUE: %d of %d loaded ", serviceRequest.currentOffset, serviceRequest.totalCount);
}
}
return; // all OK cases
}
}
}
if ([serviceRequest.delegate respondsToSelector:#selector(transactionListLoadingFailed:with:)])
[serviceRequest.delegate transactionListLoadingFailed:serviceRequest with:response.statusCode];
NSLog(#"ERROR: Loading Transactions Response Code: %ld", (long)response.statusCode);
}
Short Answer:
You are sending a message to an object that cannot validly respond to it. The stack trace is telling you that when you make the call [PaymillPaymentService handleTransactionListRequest:] that PaymillPaymentService cannot accept handleTransactionListRequest.
Long answer:
Look at the stack trace here:
5 Control 0x10005acb4 -[PaymillPaymentService handleTransactionListRequest:] (PaymillPaymentService.m:211)
This is telling you that in the file PaymillPaymentService.m on line 211 you are sending PaymillPaymentService the message handleTransactionListRequest to which it cannot validly respond. In your discussion with rmaddy, Hot Licks, and Paulc11 you mentioned that line 211 is the function entry for handleTransactionListRequest (in whatever file it resides). If that's the case it is coincidental.
If you want further follow up you need to post PaymillPaymentService.m and ensure that you include all the line numbers.

Thread Signal SIGABRT Exception

I'm curious to know why I'm receiving an exception on this code and as to what this exception means. When I remove the for loop, as indicated below, it works fine. When I include it, I get an exception.
-(void) loadVenues {
NSString *latLon = #"34.0500, -118.2500"; // approximate latLon of The Mothership (a.k.a Apple headquarters)
NSString *clientID = kCLIENTID;
NSString *clientSecret = kCLIENTSECRET;
//34.0500° N, 118.2500
NSDictionary *queryParams = #{#"ll" : latLon,
#"client_id" : clientID,
#"client_secret" : clientSecret,
#"categoryId" : #"4bf58dd8d48988d1e0931735",
#"v" : #"20140118"};
[[RKObjectManager sharedManager] getObjectsAtPath:#"/v2/venues/search"
parameters:queryParams
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
_venues = mappingResult.array;
NSMutableArray *temp = [(NSArray*)_venues mutableCopy];
for (int i =0; i < _venues.count; i++)
{
NSUInteger index = 0;
for (int j = 0; j <_venues.count; j++)
{
//((MyObjectType *) [myArray objectAtIndex:0]).intProperty = 12345;
if(((Venue *) [temp objectAtIndex:index]).location.distance > 0)
{
Venue *holder= [temp objectAtIndex:index];
[temp removeObjectAtIndex:index];
NSUInteger indexer = index +1;
[temp addObject:[temp objectAtIndex:indexer]];
//replace a with a+1
[temp replaceObjectAtIndex:indexer withObject:holder];
//[temp addObject:holder atIndex: index+1];
//a[i+1]=holder;
index++;
}
else {index++;}
}
}
_venues = temp;
[self.tableView reloadData];
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"What do you mean by 'there is no coffee?': %#", error);
}
];
}
I'm getting an exception at this line:
[temp addObject:[temp objectAtIndex:indexer]];
And I'm not sure why.
Here is the error:
2014-07-02 21:43:12.536 CoffeeKit[63581:60b] I restkit:RKLog.m:33 RestKit logging initialized...
2014-07-02 21:43:12.655 CoffeeKit[63581:60b] I restkit.network:RKObjectRequestOperation.m:150 GET 'https://api.foursquare.com/v2/venues/search?categoryId=4bf58dd8d48988d1e0931735&client_id=ZE5VJOPEO1PP3NDFVCM3O2ZUXWDDJRB20XDDGH3OETBKOVZB&client_secret=5LGY2CEASBQZQS5P0LYFICWDKMDOHJJ00F3G24LT4J4DX4X3&ll=34.0500%2C%20-118.2500&v=20140118'
2014-07-02 21:43:13.085 CoffeeKit[63581:f03] I restkit.network:RKObjectRequestOperation.m:220 GET 'https://api.foursquare.com/v2/venues/search?categoryId=4bf58dd8d48988d1e0931735&client_id=CLIENT_ID&client_secret=CLIENT_SECRET&ll=34.0500%2C%20-118.2500&v=20140118' (200 OK / 30 objects) [request=0.4171s mapping=0.0128s total=0.4486s]
2014-07-02 21:43:13.087 CoffeeKit[63581:60b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 29 beyond bounds [0 .. 28]'
*** First throw call stack:
(
0 CoreFoundation 0x00000001023a0495 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001020ff99e objc_exception_throw + 43
2 CoreFoundation 0x0000000102346745 -[__NSArrayM objectAtIndex:] + 213
3 CoffeeKit 0x0000000100002efa __34-[MasterViewController loadVenues]_block_invoke + 602
4 CoffeeKit 0x000000010009310b __66-[RKObjectRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke244 + 91
5 libdispatch.dylib 0x0000000102c9a851 _dispatch_call_block_and_release + 12
6 libdispatch.dylib 0x0000000102cad72d _dispatch_client_callout + 8
7 libdispatch.dylib 0x0000000102c9d3fc _dispatch_main_queue_callback_4CF + 354
8 CoreFoundation 0x00000001023fe289 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
9 CoreFoundation 0x000000010234b854 __CFRunLoopRun + 1764
10 CoreFoundation 0x000000010234ad83 CFRunLoopRunSpecific + 467
11 GraphicsServices 0x00000001033e2f04 GSEventRunModal + 161
12 UIKit 0x0000000100cace33 UIApplicationMain + 1010
13 CoffeeKit 0x0000000100003733 main + 115
14 libdyld.dylib 0x0000000102efe5fd start + 1
15 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
As you can see from your stack, your error is occurring because you attempt to access the object at index 29, which is outside of the array's bounds:
* -[__NSArrayM objectAtIndex:]: index 29 beyond bounds [0 .. 28]
In your case, it's probably arising from this line:
NSUInteger indexer = index +1;
[temp addObject:[temp objectAtIndex:indexer]];
Which I'm assuming you're using to get the value of the next object. Once the array reaches the 28th object, however, you attempt to access the imaginary 29th object.
Bottom line: refactor your code so that you only access objects that exist.
You are getting out of bounds by accessing the NEXT element in the array, 2 things. you can directly use 'j' to access the element (instead of index, so u dont have to increment it urself) and you can change your for from
for (int j = 0; j <_venues.count; j++)
to
for (int j = 0; j <_venues.count-1; j++)
By the way if all you need is sorting, NSMutableArray offers many options:
Rearranging Content
– exchangeObjectAtIndex:withObjectAtIndex:
– sortUsingDescriptors:
– sortUsingComparator:
– sortWithOptions:usingComparator:
– sortUsingFunction:context:
– sortUsingSelector:

CoreData: Inverse relationships causing crash on save

I have a bit of code in my application that generates a Core Data Model and populates it with a set of NSEntityDescriptions. Each of these entity descriptions then have an arbitrary number of NSPropertyDescriptions allocated for them. These properties are a combination of NSAttributeDescriptions and NSRelationshipDescriptions. All relationships are matched with an existing relationship and they are set as inverse of one another using setInverseRelationship:.
The attribute properties work fine, and to-many relationships work fine; I have tested that thoroughly. The issue seems to be with NSRelationshipDescriptions that have a maxCount value of 1, meaning the property description returns a isToMany value of NO. When the inverseRelationship property is set for these type of relationship, Core Data crashes when I try to save any object that utilizes that relationship with the error:
2013-11-09 11:17:15.068 Directory[1344:5c03] -[NSManagedObject count]: unrecognized selector sent to instance 0x9643820
2013-11-09 11:17:15.074 Directory[1344:5c03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject count]: unrecognized selector sent to instance 0x9643820'
*** First throw call stack:
(
0 CoreFoundation 0x01f9f5e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x01d228b6 objc_exception_throw + 44
2 CoreFoundation 0x0203c903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x01f8f90b ___forwarding___ + 1019
4 CoreFoundation 0x01f8f4ee _CF_forwarding_prep_0 + 14
5 CoreData 0x0083c128 -[NSSQLCore _knownOrderKeyForObject:from:inverseToMany:] + 200
6 CoreData 0x00773080 -[NSSQLCore _populateRowForOp:withObject:] + 1120
7 CoreData 0x00789157 -[NSSQLCore recordValuesForInsertedObject:] + 71
8 CoreData 0x00771e8d -[NSSQLCore recordChangesInContext:] + 685
9 CoreData 0x00770c55 -[NSSQLCore saveChanges:] + 565
10 CoreData 0x0073d88c -[NSSQLCore executeRequest:withContext:error:] + 412
11 CoreData 0x0073d380 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 4704
12 CoreData 0x00769ffc -[NSManagedObjectContext save:] + 764
13 Directory 0x0002f2bf -[ETDatabaseController save] + 111
14 Directory 0x0002ba9c -[ETDataLoader performImportWithData:] + 10284
The insinuation I am gathering from this is it is considering the inverse relationship to be a to-many relationship when that is not the case. According to my assertions, what I know about each of my relationships is:
relationDescription.inverseRelationship != nil
[relationDescription.inverseRelationship.inverseRelationship isEqual:relationDescription]
I have tested this by creating the model and populating it with a small set of sample data. Currently, objects that have any sort of attributes, to-many relationships (with/without inverse), and to-one relationship (without inverse) work consistently. The issues comes when I try to have a to-one relationship with an inverse relationship.
This seems a bit convoluted so let me know if I need to clarify anything better. Thanks!
Edit 1:
The relationship creation is done in two steps, first it creates all the relationships, then it establishes the inverse of each relationship by using a lookup.
NSRelationshipDescription *description = [[NSRelationshipDescription alloc] init];
[description setName:self.name];
[description setDestinationEntity:entity];
[description setMaxCount:(isToMany ? 0 : 1)];
[description setMinCount:0];
[description setOrdered:YES]; // See you in a minute
later...
NSEntityDescription *inverseEntity = newRelationship.destinationEntity;
NSRelationshipDescription *inverseRelationDescription = [inverseEntity relationshipsByName][inverse.name];
if (inverseRelationDescription) {
inverseRelationDescription.inverseRelationship = newRelationship;
newRelationship.inverseRelationship = inverseRelationDescription;
} else if ([inverse.name isEqualToString:relation.name]) {
newRelationship.inverseRelationship = newRelationship;
}
Well, I guess writing Edit 1 made something click. So from what it looks like, if you call setOrdered: on a NSRelationDescription that is meant to be a to-one relationship, the internals of Core Data automatically considers it a to-many relationship, despite the conflict with the maxCount being one.
I fixed this by changing the creation code for the relationship from:
NSRelationshipDescription *description = [[NSRelationshipDescription alloc] init];
[description setName:self.name];
[description setDestinationEntity:entity];
[description setMaxCount:(isToMany ? 0 : 1)];
[description setMinCount:0];
[description setOrdered:YES];
to:
NSRelationshipDescription *description = [[NSRelationshipDescription alloc] init];
[description setName:self.name];
[description setDestinationEntity:entity];
[description setMaxCount:(isToMany ? 0 : 1)];
[description setMinCount:0];
if (isToMany)
[description setOrdered:YES];

Resources