I am going crazy trying to debug this. I am trying to basically duplicate a row in my SQLite db and increment a value. I have used similar insert statements elsewhere in my code and had no problems, but this time it is not cooperating. The program errors when it gets to the executeUpdate statement.
I am relatively new to iOS programming and have gone as far as I can on my own.
Here is my function:
+ (BOOL)updatePetWithNewVet:(NSNumber *)i {
NSString *appSupportDir = [NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES) lastObject];
NSString *dbPath = [appSupportDir stringByAppendingPathComponent:#"pets.sqlite"];
FMDatabase *database = [FMDatabase databaseWithPath:dbPath];
[database open];
FMResultSet *results = [database executeQuery:#"Select * from vets order by vetID desc limit 1"];
if ([results next]) {
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSInteger vID = [results intForColumn:#"vetID"];
NSInteger vID2 = vID+1;
NSNumber *newVetID = [NSNumber numberWithInteger:vID2];
NSString *vName = [results stringForColumn:#"vetName"];
NSString *vPhone = [results stringForColumn:#"vetPhone"];
NSString *vStreet = [results stringForColumn:#"vetStreet"];
NSString *vCity = [results stringForColumn:#"vetCity"];
NSString *vState = [results stringForColumn:#"vetState"];
NSNumber *vZipcode = [f numberFromString:[results stringForColumn:#"vetZipcode"]];
NSLog(#"%#", vName);
NSLog(#"%#", vPhone);
NSLog(#"%#", vStreet);
NSLog(#"%#", vCity);
NSLog(#"%#", vState);
NSLog(#"%#", vZipcode);
NSLog(#"VET ID: %ld", (long)vID);
NSLog(#"NEW VET ID: %#", newVetID);
[results close];
[database executeUpdateWithFormat:#"INSERT INTO vets (vetID, vetName, vetPhone, vetStreet, vetCity, vetState, vetZipcode) Values (?, ?, ?, ?, ?, ?, ?)", newVetID, vName, vPhone, vStreet, vCity, vState, vZipcode, nil];
NSLog(#"%#", [database lastErrorMessage]);
}
[database close];
return 1;
}
And it is not working. This is what get when I crash:
2014-11-29 09:35:54.722 PetJournal[58823:8400345] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
*** First throw call stack:
(
0 CoreFoundation 0x000000010eb37f35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010e7d0bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010ea22f33 -[__NSArrayM objectAtIndex:] + 227
3 PetJournal 0x000000010cc1744e -[FMDatabase executeUpdate:error:withArgumentsInArray:orDictionary:orVAList:] + 2542
4 PetJournal 0x000000010cc17fa8 -[FMDatabase executeUpdate:withArgumentsInArray:] + 152
5 PetJournal 0x000000010cc1834d -[FMDatabase executeUpdateWithFormat:] + 637
6 PetJournal 0x000000010cc54fd7 +[UIView(Database) updatePetWithNewVet:] + 1159
7 PetJournal 0x000000010cc549d2 +[UIView(Database) createPetNamed:withBirthday:] + 1522
8 PetJournal 0x000000010cc3165e -[AddPetViewController savePet:] + 398
9 UIKit 0x000000010d07a8be -[UIApplication sendAction:to:from:forEvent:] + 75
10 UIKit 0x000000010d181410 -[UIControl _sendActionsForEvents:withEvent:] + 467
11 UIKit 0x000000010d1807df -[UIControl touchesEnded:withEvent:] + 522
12 UIKit 0x000000010d0c0308 -[UIWindow _sendTouchesForEvent:] + 735
13 UIKit 0x000000010d0c0c33 -[UIWindow sendEvent:] + 683
14 UIKit 0x000000010d08d9b1 -[UIApplication sendEvent:] + 246
15 UIKit 0x000000010d09aa7d _UIApplicationHandleEventFromQueueEvent + 17370
16 UIKit 0x000000010d076103 _UIApplicationHandleEventQueue + 1961
17 CoreFoundation 0x000000010ea6d551 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
18 CoreFoundation 0x000000010ea6341d __CFRunLoopDoSources0 + 269
19 CoreFoundation 0x000000010ea62a54 __CFRunLoopRun + 868
20 CoreFoundation 0x000000010ea62486 CFRunLoopRunSpecific + 470
21 GraphicsServices 0x00000001114139f0 GSEventRunModal + 161
22 UIKit 0x000000010d079420 UIApplicationMain + 1282
23 PetJournal 0x000000010cc33f63 main + 115
24 libdyld.dylib 0x000000010f2d2145 start + 1
25 ??? 0x0000000000000001 0x0 + 1
)
You are using executeUpdateWithFormat, but are not using printf-style syntax in your SQL. Either use executeUpdateWithFormat with printf-style format string, or use executeUpdate with the ? placeholders.
Personally, I'd suggest you just use executeUpdate (and drop the nil from the end of the list).
Related
I have a viewController that manages a UICollectionView. I have a helper method that is called from cellForItemAtIndexPath that provides an NSAttributedString for a label in the cell. The helper method formats an NSAttributedString from an html string. The app will crash when moving to the background, but only if the indexPath.item is greater than 1. In other words, I can exit the app without crashing from the first or second cell, but crash consistently on the third, forth, ... cell.
Here are my helper method and stack trace. Any idea why I am crashing on exiting the app?
#pragma mark - === Utility Methods === -
- (NSAttributedString *)stepDescriptionStringForIndexPath:(NSIndexPath *)indexPath {
NSString *headerString;
NSString *htmlString;
NSString *categoryString = [NSString stringWithFormat:#"Category: %#", self.knot.category.categoryName];
NSString *abokString = [NSString stringWithFormat:#"ABOK #: %#", self.knot.abokNumber];
NSMutableString *activitiesString = [NSMutableString stringWithCapacity:10];
[activitiesString appendString:#"Activities: "];
// build a string of activities to append to the description html
NSArray *activities = [self.knot.activities allObjects];
if ([activities count] > 0) {
int counter = 1;
for (Activity *activity in activities) {
[activitiesString appendString:activity.activityName];
if (counter < [activities count]) {
[activitiesString appendString:#", "];
}
counter ++;
}
}
// build an HTML string by concatinating the activities to the step description
// and add the header string
if(indexPath.item > 0){
Step *step = (Step *)self.steps[indexPath.item - 1];
headerString = [NSString stringWithFormat:#"Step %ld of %lu", (long)indexPath.item, (unsigned long)[self.steps count]];
htmlString =[NSString stringWithFormat:#"<p>%#</p>%#", headerString, step.stepDescription];
} else {
headerString = #"Overview";
htmlString = [NSString stringWithFormat:#"<p>%#</p>%#<p>%#</br>%#</br>%#</p>", headerString, self.knot.knotDescription, categoryString, abokString, activitiesString];
}
// convert the html string to an attributed string
NSMutableAttributedString *attrStringFromHTML = [[NSMutableAttributedString alloc] initWithData:[htmlString dataUsingEncoding:NSUTF8StringEncoding]
options:#{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]}
documentAttributes:nil
error:nil];
// set the font for the body
NSRange totalRange;
totalRange.location = 0;
totalRange.length = attrStringFromHTML.length;
[attrStringFromHTML addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:16] range:totalRange];
// set the font for the header
NSString *temp = [attrStringFromHTML string];
NSRange headerRange = [temp rangeOfString:headerString];
NSRange categoryRange = [temp rangeOfString:categoryString];
NSRange abokRange = [temp rangeOfString:abokString];
NSRange activitiesRange = [temp rangeOfString:activitiesString];
[attrStringFromHTML addAttribute:NSFontAttributeName value:[UIFont boldSystemFontOfSize:18] range:headerRange];
//set the font for the activities paragraph
if(indexPath.item == 1){
[attrStringFromHTML addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:categoryRange];
[attrStringFromHTML addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:abokRange];
[attrStringFromHTML addAttribute:NSFontAttributeName value:[UIFont systemFontOfSize:12] range:activitiesRange];
}
return attrStringFromHTML;
}
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'unexpected start state'
*** First throw call stack:
(
0 CoreFoundation 0x00000001131aad85 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000112c1edeb objc_exception_throw + 48
2 CoreFoundation 0x00000001131aabea +[NSException raise:format:arguments:] + 106
3 Foundation 0x0000000110b96e1e -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:] + 169
4 UIKit 0x00000001113a7d4e _prepareForCAFlush + 256
5 UIKit 0x00000001113b40b4 _beforeCACommitHandler + 12
6 CoreFoundation 0x00000001130cfc37 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
7 CoreFoundation 0x00000001130cfba7 __CFRunLoopDoObservers + 391
8 CoreFoundation 0x00000001130c511c CFRunLoopRunSpecific + 524
9 UIFoundation 0x000000011a697a7a -[NSHTMLReader _loadUsingWebKit] + 2093
10 UIFoundation 0x000000011a698e74 -[NSHTMLReader attributedString] + 22
11 UIFoundation 0x000000011a6323c0 _NSReadAttributedStringFromURLOrData + 5623
12 UIFoundation 0x000000011a630d34 -[NSAttributedString(NSAttributedStringUIFoundationAdditions) initWithData:options:documentAttributes:error:] + 115
13 WhatKnotToDo 0x000000010e84d3ac -[CSC_iPad_KnotDetailViewController stepDescriptionStringForIndexPath:] + 2476
14 WhatKnotToDo 0x000000010e84c31d -[CSC_iPad_KnotDetailViewController collectionView:cellForItemAtIndexPath:] + 477
15 UIKit 0x0000000111bff08f -[UICollectionView _createPreparedCellForItemAtIndexPath:withLayoutAttributes:applyAttributes:isFocused:] + 483
16 UIKit 0x0000000111c02d96 -[UICollectionView _updateVisibleCellsNow:] + 4988
17 UIKit 0x0000000111c07575 -[UICollectionView layoutSubviews] + 258
18 UIKit 0x0000000111442980 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 703
19 QuartzCore 0x0000000112af6c00 -[CALayer layoutSublayers] + 146
20 QuartzCore 0x0000000112aeb08e _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 366
21 QuartzCore 0x0000000112aeaf0c _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
22 QuartzCore 0x0000000112adf3c9 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 277
23 QuartzCore 0x0000000112b0d086 _ZN2CA11Transaction6commitEv + 486
24 UIKit 0x0000000111394a0b __65-[UIApplication _beginSnapshotSessionForScene:withSnapshotBlock:]_block_invoke2222 + 601
25 UIKit 0x0000000111395201 __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke2243 + 131
26 FrontBoardServices 0x00000001153e3039 -[FBSSceneSnapshotAction _finishAllRequests] + 65
27 FrontBoardServices 0x00000001153e2de3 -[FBSSceneSnapshotAction executeRequestsWithHandler:completionHandler:expirationHandler:] + 218
28 UIKit 0x0000000111395024 __65-[UIApplication _performSnapshotsWithAction:forScene:completion:]_block_invoke + 305
29 UIKit 0x0000000111394592 -[UIApplication _beginSnapshotSessionForScene:withSnapshotBlock:] + 1138
30 UIKit 0x0000000111394eb2 -[UIApplication _performSnapshotsWithAction:forScene:completion:] + 629
31 UIKit 0x0000000111394bbc -[UIApplication _handleSnapshotAction:forScene:completion:] + 153
32 UIKit 0x0000000111390a8f __102-[UIApplication _handleApplicationDeactivationWithScene:shouldForceExit:transitionContext:completion:]_block_invoke1993 + 290
33 UIKit 0x0000000111390657 __102-[UIApplication _handleApplicationDeactivationWithScene:shouldForceExit:transitionContext:completion:]_block_invoke1979 + 1258
34 UIKit 0x0000000111393f62 _runAfterCACommitDeferredBlocks + 317
35 UIKit 0x00000001113a7e4c _cleanUpAfterCAFlushAndRunDeferredBlocks + 95
36 UIKit 0x00000001113b4147 _afterCACommitHandler + 90
37 CoreFoundation 0x00000001130cfc37 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
38 CoreFoundation 0x00000001130cfba7 __CFRunLoopDoObservers + 391
39 CoreFoundation 0x00000001130c57fb __CFRunLoopRun + 1147
40 CoreFoundation 0x00000001130c50f8 CFRunLoopRunSpecific + 488
41 GraphicsServices 0x0000000115203ad2 GSEventRunModal + 161
42 UIKit 0x0000000111387f09 UIApplicationMain + 171
43 WhatKnotToDo 0x000000010e820b7f main + 111
44 libdyld.dylib 0x000000011396592d start + 1
45 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
I've come across this issue too, after a few hours, i've found a solution for this one.
You'll just need to wrap the code for converting the NSAttributedString into dispatch_async.
For example:
DispatchQueue.MainQueue.DispatchAsync(() =>
{
var encodingData = ((NSString)html).Encode(NSStringEncoding.Unicode, true);
NSAttributedString data = new NSAttributedString(
encodingData,
new NSAttributedStringDocumentAttributes()
{
DocumentType = NSDocumentType.HTML,
}, ref error);
});
I'm using Xamarin, so these are C# code, but i believe they're similar in Swift and Obj C.
Look like when the system is making transition between pages (view controller), it will try to prevent any heavy task running on UI Thread. Which cause this issue.
I have two modes - Mode 1 and Mode 2 which can be switched by a central button. Switch between modes allows user to see two different types of clustered annotations.
I can switch from Mode 1 to Mode 2 easily, but when I switch back to Mode 1 I'm getting this nasty error
-[__NSCFDictionary componentsSeparatedByString:]: unrecognized selector sent to instance 0x7fb1308cca50
I'm opening my code and in the TBClusteredAnnotations.m (script I'm using for clusterization). I have the following snippet of code relating to componentsSeparatedByString:
TBQuadTreeNodeData TBDataFromLine(NSString *line)
{
NSString *separator=#">>>>>>>>";
NSArray *components = [line componentsSeparatedByString: separator];
double latitude = [components[0] doubleValue];
double longitude = [components[1] doubleValue];
TBUserInfo* userInfo = malloc(sizeof(TBUserInfo));
NSString *userName = [components[2] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
userInfo->userId = malloc(sizeof(char) * userName.length + 1);
strncpy(userInfo->userId, [userName UTF8String], userName.length + 1);
NSString *userId = [components [3] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
userInfo->userImage = malloc(sizeof(char) * userId.length + 1);
strncpy(userInfo->userImage, [userId UTF8String], userId.length + 1);
return TBQuadTreeNodeDataMake(latitude, longitude, userInfo);
}
but I'm loading my annotations with the following code in the MainViewController:
-(void)annotationsmode1:(NSMutableArray*)marr
{
if(marr.count>0)
{
NSMutableArray *newMarr1=[NSMutableArray new];
NSString *separatestuff=#">>>>>>>>";
for(NSMutableDictionary *dic in marr)
{
NSString *newStr=[NSString stringWithFormat:#"%#%#",[dic[#"latitude"] isEqualToString:#""]?#" ":dic[#"latitude"],separatestuff];
newStr=[NSString stringWithFormat:#"%#%#%#",newStr,[dic[#"longitude"] isEqualToString:#""]?#" ":dic[#"longitude"],separatestuff];
newStr=[NSString stringWithFormat:#"%#%#%#",newStr,[dic[#"id"] isEqualToString:#""]?#" ":dic[#"id"],separatestuff];
newStr=[NSString stringWithFormat:#"%#%#",newStr,[dic[#"image"] isEqualToString:#""]?#" ":dic[#"image"]];
[newMarr1 addObject:newStr];
}
//NSLog(#"NEW Array: %#",newMarr);
[self.coordinateQuadTree buildTree:newMarr1];
}
}
-(void)annotationsmode2:(NSMutableArray*)marr
{
if(marr.count>0)
{
NSMutableArray *newMarr=[NSMutableArray new];
NSString *separatestuff2=#">>>>>>>>";
for(NSMutableDictionary *dic in marr)
{
NSString *newStr=[NSString stringWithFormat:#"%#%#",[dic[#"lat"] isEqualToString:#""]?#" ":dic[#"lat"],separatestuff2];
newStr=[NSString stringWithFormat:#"%#%#%#",newStr,[dic[#"lang"] isEqualToString:#""]?#" ":dic[#"lang"],separatestuff2];
newStr=[NSString stringWithFormat:#"%#%#%#",newStr,[dic[#"id"] isEqualToString:#""]?#" ":dic[#"id"],separatestuff2];
newStr=[NSString stringWithFormat:#"%#%#",newStr,[dic[#"image"] isEqualToString:#""]?#" ":dic[#"image"]];
[newMarr addObject:newStr];
}
//NSLog(#"NEW Array: %#",newMarr);
[self.coordinateQuadTree buildTree:newMarr];
}
}
UPDATE: This is the block of code where the TBDataFromLine is used
- (void)buildTree:(NSMutableArray *)lines
{
#autoreleasepool {
NSInteger count = lines.count - 1;
TBQuadTreeNodeData *dataArray = malloc(sizeof(TBQuadTreeNodeData) * count);
for (NSInteger i = 0; i < count; i++) {
dataArray[i] = TBDataFromLine(lines[i]);
}
//TBBoundingBox world = TBBoundingBoxMake(19, -166, 72, -53);
TBBoundingBox world = TBBoundingBoxMake(0,0,100,100);
_root = TBQuadTreeBuildWithData(dataArray, count, world, 4);
}
}
I've been working on this issue for hours now and still have no clue.
UPDATE: Here is the debugger's log I'm getting
2015-06-20 19:40:23.759 MapProject[13426:395344] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary componentsSeparatedByString:]: unrecognized selector sent to instance 0x7fdf93775680'
*** First throw call stack:
(
0 CoreFoundation 0x0000000112699c65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001121c3bb7 objc_exception_throw + 45
2 CoreFoundation 0x00000001126a10ad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x00000001125f713c ___forwarding___ + 988
4 CoreFoundation 0x00000001125f6cd8 _CF_forwarding_prep_0 + 120
5 MapProject 0x000000010f469ac4 TBDataFromLine + 84
6 MapProject 0x000000010f46a36f -[TBCoordinateQuadTree buildTree:] + 191
7 MapProject 0x000000010f3d2503 -[MMViewController findSpot:] + 771
8 UIKit 0x0000000110a52da2 -[UIApplication sendAction:to:from:forEvent:] + 75
9 UIKit 0x0000000110b6454a -[UIControl _sendActionsForEvents:withEvent:] + 467
10 UIKit 0x0000000110b63919 -[UIControl touchesEnded:withEvent:] + 522
11 UIKit 0x0000000110a9f998 -[UIWindow _sendTouchesForEvent:] + 735
12 UIKit 0x0000000110aa02c2 -[UIWindow sendEvent:] + 682
13 UIKit 0x0000000110a66581 -[UIApplication sendEvent:] + 246
14 UIKit 0x0000000110a73d1c _UIApplicationHandleEventFromQueueEvent + 18265
15 UIKit 0x0000000110a4e5dc _UIApplicationHandleEventQueue + 2066
16 CoreFoundation 0x00000001125cd431 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
17 CoreFoundation 0x00000001125c32fd __CFRunLoopDoSources0 + 269
18 CoreFoundation 0x00000001125c2934 __CFRunLoopRun + 868
19 CoreFoundation 0x00000001125c2366 CFRunLoopRunSpecific + 470
20 GraphicsServices 0x000000011444da3e GSEventRunModal + 161
21 UIKit 0x0000000110a51900 UIApplicationMain + 1282
22 MapProject 0x000000010f474c2f main + 111
23 libdyld.dy
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Add an Exception break point and it will take to exactly to that line where that crash is happening. Also check 'line' cause it is changed to dictionary but you code expect it
to be a string
There is no [] operator on NSArray or NSMutableArray.
You need this:
for (NSInteger i = 0; i < count; i++) {
dataArray[i] = TBDataFromLine([lines objectAtIndex:i]);
}
Using [] on NSArray* effectively acted like "lines" was really a pointer to an array of NSMutableArray instances, whereas you wanted to get one of the items out of the array to which it pointed.
Using Chat Application with XMPPFramework Iam getting This Error
Message SendButton Action as given below, plz help me if any one have idea then tell me plz..............
- (IBAction)sendAction:(id)sender
{
if([_chatTextField.text length] > 0)
{
NSString* po = getUser.ofUser;
bubbleTable.typingBubble = NSBubbleTypingTypeNobody;
NSBubbleData *messageBubble = [NSBubbleData dataWithText:_chatTextField.text date:[NSDate dateWithTimeIntervalSinceNow:0] type:BubbleTypeMine];
[bubbleData addObject:messageBubble];
[bubbleTable reloadData];
[bubbleTable scrollBubbleViewToBottomAnimated:YES];
[[QuoteMessageController SharedInstance] SendChatMessageTo:getUser.account withContent:_chatTextField.text toUserId:[NSString stringWithFormat:#"%ld", (long)getUser.Id] andOFId:po andVerifyKey:chatMessageKey];
}
Getting error in output as given bellow>>>>>>
*** First throw call stack:
(
0 CoreFoundation 0x000000010e18ff35 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010da7bbb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010e18fe6d +[NSException raise:format:] + 205
3 Foundation 0x000000010ba211f8 -[NSString stringByAppendingString:] + 96
4 SourceSage 0x000000010ae0c939 +[SSWriteReadInDb writeQuotesTable:UserImageUrl:UserId:OfUser:] + 409
5 SourceSage 0x000000010adb8d56 -[QuoteMessageController SendChatMessageTo:withContent:toUserId:andOFId:andVerifyKey:] + 2454
6 SourceSage 0x000000010ad6ac30 -[SSChatViewController sendAction:] + 752
7 UIKit 0x000000010beb48be -[UIApplication sendAction:to:from:forEvent:] + 75
8 UIKit 0x000000010bfbb410 -[UIControl _sendActionsForEvents:withEvent:] + 467
9 UIKit 0x000000010bfba7df -[UIControl touchesEnded:withEvent:] + 522
10 UIKit 0x000000010befa308 -[UIWindow _sendTouchesForEvent:] + 735
11 UIKit 0x000000010befac33 -[UIWindow sendEvent:] + 683
12 UIKit 0x000000010bec79b1 -[UIApplication sendEvent:] + 246
13 UIKit 0x000000010bed4a7d _UIApplicationHandleEventFromQueueEvent + 17370
14 UIKit 0x000000010beb0103 _UIApplicationHandleEventQueue + 1961
15 CoreFoundation 0x000000010e0c5551 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
16 CoreFoundation 0x000000010e0bb41d __CFRunLoopDoSources0 + 269
17 CoreFoundation 0x000000010e0baa54 __CFRunLoopRun + 868
18 CoreFoundation 0x000000010e0ba486 CFRunLoopRunSpecific + 470
19 GraphicsServices 0x000000010fe7c9f0 GSEventRunModal + 161
20 UIKit 0x000000010beb3420 UIApplicationMain + 1282
21 SourceSage 0x000000010ae02893 main + 115
22 libdyld.dylib 0x000000010ee2e145 start + 1
23 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
After looking at this part of your stack trace:
2 CoreFoundation 0x000000010e18fe6d +[NSException raise:format:] + 205
3 Foundation 0x000000010ba211f8 -[NSString stringByAppendingString:] + 96
4 SourceSage 0x000000010ae0c939 +[SSWriteReadInDb writeQuotesTable:UserImageUrl:UserId:OfUser:] + 409
5 SourceSage 0x000000010adb8d56 -[QuoteMessageController SendChatMessageTo:withContent:toUserId:andOFId:andVerifyKey:] + 2454
6 SourceSage 0x000000010ad6ac30 -[SSChatViewController sendAction:] + 752
You'll see the exception is raised after a string is appended to a string. That is usually caused from appending nil to the string. By guess is that one of your NSString arguments that you're sending to the method below is nil.
[[QuoteMessageController SharedInstance] SendChatMessageTo:getUser.account
withContent:_chatTextField.text
toUserId:[NSString stringWithFormat:#"%ld", (long)getUser.Id]
andOFId:po
andVerifyKey:chatMessageKey];
To find out if this is in fact the case, either set a breakpoint here and check all the values, or add in the following before you call this method:
NSLog(#"%#", getUser.account);
NSLog(#"%#", _chatTextField.text);
NSLog(#"%#", po);
NSLog(#"%#", [NSString stringWithFormat:#"%ld", (long)getUser.Id]);
NSLog(#"%#", chatMessageKey);
I don't know what your parameters actually are, so remove the NSLogs for the variables that are not NSString. If one of these logs come back as nil or null (I forget what the console will output), then you found your issue. If it's an argument that you don't necessarily need, you should pass an empty NSString instead. I usually do this with a ternary. So assuming the culprit is _chatTextField.text, I would pass that argument as:
[[QuoteMessageController SharedInstance] SendChatMessageTo:getUser.account
withContent:_chatTextField.text ?: #""
toUserId:[NSString stringWithFormat:#"%ld", (long)getUser.Id]
andOFId:po
andVerifyKey:chatMessageKey];
Doing this basically says, if _chatTextField.text is true (which it will equate to if it is not nill), use that value, otherwise use #""
EDIT:
- (IBAction)sendAction:(id)sender
{
if([_chatTextField.text length] > 0)
{
NSString* po = getUser.ofUser ?: #"";
NSString *acct = getUser.account ?: #"";
bubbleTable.typingBubble = NSBubbleTypingTypeNobody;
NSBubbleData *messageBubble = [NSBubbleData dataWithText:_chatTextField.text date:[NSDate dateWithTimeIntervalSinceNow:0] type:BubbleTypeMine];
[bubbleData addObject:messageBubble];
[bubbleTable reloadData];
[bubbleTable scrollBubbleViewToBottomAnimated:YES];
[[QuoteMessageController SharedInstance] SendChatMessageTo:acct withContent:_chatTextField.text toUserId:[NSString stringWithFormat:#"%ld", (long)getUser.Id] andOFId:po andVerifyKey:chatMessageKey];
}
My app is working great, the only issue i have right now it's with the live data viewer, if nothing is happening the XML file is empty, and the app displays nothing to show right now, if it has 2 or 2000 events happening, it displays in my live data viewer, if there is only a single event occurring my app crashes when i got to that view.
I have compared the XML structures and they are the same for 1 or 2+ events.
I have included below my XML parser method, my cellForRowAtIndexPath and my numberOfRows method.
Is there anyone out there that can see what's the issue? I remind you again, this only crashes if my XML file has a single Match node. Works fine with 0 or 100000 but not with 1.
At the end you will also find the crash report, i hope it's useful in finding the problem and fixing it.
Thank you.
-(void) parseXMLLiveMatch
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"something.xml"]];
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *xmlString = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
NSDictionary *xml = [NSDictionary dictionaryWithXMLString:xmlString];
NSMutableArray *items = [xml objectForKey:#"Match"];
NSMutableArray *newLiveMatchArray = [[NSMutableArray alloc] init];
for (NSDictionary *dict in items) {
NSLog(#"%# %#", [dict class], dict);
LiveMatchObject *myMatches = [LiveMatchObject matchesFromXMLDictionary:dict];
[newLiveMatchArray addObject:myMatches];
}
NSNull *nullValue = [NSNull null];
[newLiveMatchArray insertObject:nullValue atIndex:0];
[self setTableDataLiveMatch:newLiveMatchArray];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"LiveIdent";
LiveViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
LiveMatchObject *item = [tableDataLiveMatch objectAtIndex:(int)([indexPath row]/2)];
...
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return tableDataLiveMatch.count * 2;
}
2014-02-17 14:40:56.419 Liga Zon Sagres Companion[2539:70b] __NSCFString HomeGoals
2014-02-17 14:40:56.420 Liga Zon Sagres Companion[2539:70b] -[__NSCFString objectForKeyedSubscript:]: unrecognized selector sent to instance 0x10d03d7f0
2014-02-17 14:40:56.424 Liga Zon Sagres Companion[2539:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString objectForKeyedSubscript:]: unrecognized selector sent to instance 0x10d03d7f0'
*** First throw call stack:
(
0 CoreFoundation 0x00000001019df795 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000101742991 objc_exception_throw + 43
2 CoreFoundation 0x0000000101a70bad -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x00000001019d109d ___forwarding___ + 973
4 CoreFoundation 0x00000001019d0c48 _CF_forwarding_prep_0 + 120
5 Liga Zon Sagres Companion 0x00000001000014da +[LiveMatchObject matchesFromXMLDictionary:] + 138
6 Liga Zon Sagres Companion 0x0000000100003da6 -[LiveTableViewController parseXMLLiveMatch] + 790
7 Liga Zon Sagres Companion 0x0000000100003a48 -[LiveTableViewController viewWillAppear:] + 88
8 UIKit 0x00000001004943f4 -[UIViewController _setViewAppearState:isAnimating:] + 394
9 UIKit 0x00000001004c0ce5 -[UITabBarController transitionFromViewController:toViewController:transition:shouldSetSelected:] + 524
10 UIKit 0x00000001004bd155 -[UITabBarController _setSelectedViewController:] + 259
11 UIKit 0x00000001004c046c -[UITabBarController _tabBarItemClicked:] + 248
12 UIKit 0x00000001003a6096 -[UIApplication sendAction:to:from:forEvent:] + 80
13 UIKit 0x00000001003a6044 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 17
14 UIKit 0x00000001005fb4cc -[UITabBar _sendAction:withEvent:] + 420
15 UIKit 0x00000001003a60ae -[UIApplication sendAction:to:from:forEvent:] + 104
16 UIKit 0x00000001003a6044 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 17
17 UIKit 0x000000010047a450 -[UIControl _sendActionsForEvents:withEvent:] + 203
18 UIKit 0x00000001003a6096 -[UIApplication sendAction:to:from:forEvent:] + 80
19 UIKit 0x00000001003a6044 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 17
20 UIKit 0x000000010047a450 -[UIControl _sendActionsForEvents:withEvent:] + 203
21 UIKit 0x00000001004799c0 -[UIControl touchesEnded:withEvent:] + 530
22 UIKit 0x00000001003dac15 -[UIWindow _sendTouchesForEvent:] + 701
23 UIKit 0x00000001003db633 -[UIWindow sendEvent:] + 988
24 UIKit 0x00000001003b4fa2 -[UIApplication sendEvent:] + 211
25 UIKit 0x00000001003a2d7f _UIApplicationHandleEventQueue + 9549
26 CoreFoundation 0x000000010196eec1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
27 CoreFoundation 0x000000010196e792 __CFRunLoopDoSources0 + 242
28 CoreFoundation 0x000000010198a61f __CFRunLoopRun + 767
29 CoreFoundation 0x0000000101989f33 CFRunLoopRunSpecific + 467
30 GraphicsServices 0x000000010300b3a0 GSEventRunModal + 161
31 UIKit 0x00000001003a5043 UIApplicationMain + 1010
32 Liga Zon Sagres Companion 0x000000010001fce3 main + 115
33 libdyld.dylib 0x000000010232b5fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
Cheers and thank you.
As resquested:
#implementation LiveMatchObject
#synthesize homeGoals, awayGoals, homeName, awayName, matchDate, matchMinute, matchStatus, homeTeamLogo, awayTeamLogo, spectators, round, homeStartingGoalie, homeStartingDefense, homeStartingMiddlefield, homeStartingFoward, homeFormation, awayStartingGoalie, awayStartingDefense, awayStartingMiddlefield, awayStartingFoward, awayFormation;
+(LiveMatchObject *)matchesFromXMLDictionary:(NSDictionary *)dict{
LiveMatchObject *object =[[LiveMatchObject alloc]init];
object.homeGoals = dict[#"HomeGoals"];
object.awayGoals = dict[#"AwayGoals"];
object.homeName = dict[#"Hometeam"];
object.awayName = dict[#"Awayteam"];
object.matchDate = dict[#"Date"];
object.matchMinute = dict[#"Time"];
object.matchStatus = [UIImage imageNamed:dict[#"Time"]];
object.homeTeamLogo = [UIImage imageNamed:dict[#"HomeTeam_Id"]];
object.awayTeamLogo = [UIImage imageNamed:dict[#"AwayTeam_Id"]];
object.spectators = dict[#"Spectators"];
object.round = dict[#"Round"];
object.homeFormation = dict[#"HomeTeamFormation"];
object.homeStartingGoalie = dict[#"HomeLineupGoalkeeper"];
object.homeStartingMiddlefield = dict[#"HomeLineupMidfield"];
object.homeStartingFoward = dict[#"HomeLineupForward"];
object.awayFormation = dict[#"AwayTeamFormation"];
object.awayStartingGoalie = dict[#"AwayLineupGoalkeeper"];
object.awayStartingMiddlefield = dict[#"AwayLineupMidfield"];
object.awayStartingFoward = dict[#"AwayLineupForward"];
return object;
}
#end
The XML
<CREPERR.COM >
<Match>
<Id>327080</Id>
<Date>2014-02-17T12:00:00-08:00</Date>
<League>Primeira Liga</League>
<Round>19</Round>
<Spectators/>
<Hometeam>Estoril-Praia</Hometeam>
<HomeTeam_Id>529</HomeTeam_Id>
<Awayteam>Braga</Awayteam>
<AwayTeam_Id>521</AwayTeam_Id>
<Time>9'</Time>
<HomeGoals>0</HomeGoals>
<AwayGoals>0</AwayGoals>
<HomeGoalDetails/>
<AwayGoalDetails/>
<HomeLineupGoalkeeper>Vagner</HomeLineupGoalkeeper>
<AwayLineupGoalkeeper>Eduardo</AwayLineupGoalkeeper>
<HomeLineupDefense>Yohan Tavares; Mano; Babanco; Ruben;</HomeLineupDefense>
<AwayLineupDefense>
Nurio; Aleksandar Miljkovic; Nuno André Coelho; Vincent Sasso;
</AwayLineupDefense>
<HomeLineupMidfield>
Javier Balboa; Goebel Evandro; Carlitos; Diogo Amado; Goncalo;
</HomeLineupMidfield>
<AwayLineupMidfield>
Custodio; Mauro; Leandro Kappel; Felipe Pardo; Alan;
</AwayLineupMidfield>
<HomeLineupForward>Seba;</HomeLineupForward>
<AwayLineupForward>Raul Andrei Rusescu;</AwayLineupForward>
<HomeSubDetails/>
<AwaySubDetails/>
<HomeTeamFormation>4-2-3-1</HomeTeamFormation>
<AwayTeamFormation>4-2-3-1</AwayTeamFormation>
<Location>Estádio António Coimbra da Mota</Location>
<Stadium>Estádio António Coimbra da Mota</Stadium>
<HomeTeamYellowCardDetails/>
<AwayTeamYellowCardDetails/>
<HomeTeamRedCardDetails/>
<AwayTeamRedCardDetails/>
</Match>
<AccountInformation>
Data requested at 2/17/2014
</AccountInformation>
</CREPERR.COM>
You are crashing because when there is only one object in your array the dict object is an NSString, not an NSDictionary. NSString does not respond the the string[#"Something"] interface, and therefore is crashing your application.
One way to test for this is:
+(LiveMatchObject *)matchesFromXMLDictionary:(NSDictionary *)dict{
if([dict isKindOfClass:[NSDictionary class]])
{
//This is a valid dictionary
}
else
{
//This is not a dictionary object, do something different
}
}
Why you are getting an NSString here instead of an NSDictionary I have no idea, and how you deal with it to get your data out in the same fashion is another question. You are going to have to set a breakpoint in there and see what NSString you are getting and what to do with it.
Very strange behaviour...I've used before an NSNumber category called NSNumber+Currencies. Yesterday I've changed everything including core data to NSDecimalNumber so I have now a class NSDecimalNumber+Currencies. There is really no link at all! to NSNumber+Currencies anymore. However if I delete it and try to run my app in the simulator, my app crashes with the message "unrecognized selector sent to instance ..." This instance is a NSDecimalNumber and the methods I use in this category are basically the same as before. And I really import ONLY the NSDecimalNumber+Currencies. But it makes no sense...I've deleted the app from the simulator, cleaned my project, closed Xcode, removed the old category even manually from the build phases but nothing helps..is there another trick? If I leave this old category in it it runs smoothly...
My error log. However after the 2nd run my app doesn't start at all and the error message is a different one:
2014-01-28 11:51:29.458 NetIncome[2341:70b] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 0 beyond bounds for empty array'
*** First throw call stack:
(
0 CoreFoundation 0x01ecf5e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x01abe8b6 objc_exception_throw + 44
2 CoreFoundation 0x01e839c2 -[__NSArrayI objectAtIndex:] + 210
3 CoreData 0x01899c1f -[NSFetchedResultsController objectAtIndexPath:] + 255
4 NetIncome 0x00003dee -[MainCategoriesViewController tableView:cellForRowAtIndexPath:] + 206
5 UIKit 0x003ac61f -[UITableView _createPreparedCellForGlobalRow:withIndexPath:] + 412
6 UIKit 0x003ac6f3 -[UITableView _createPreparedCellForGlobalRow:] + 69
7 UIKit 0x00390774 -[UITableView _updateVisibleCellsNow:] + 2378
8 UIKit 0x0038eb81 -[UITableView _updateVisibleCellsImmediatelyIfNecessary] + 66
9 UIKit 0x0039cb5f -[UITableView _visibleCells] + 35
10 UIKit 0x0039cbb4 -[UITableView visibleCells] + 33
11 UIKit 0x0039fcc0 -[UITableView setSeparatorStyle:] + 115
12 NetIncome 0x000037d4 -[MainCategoriesViewController styleTableView] + 100
13 NetIncome 0x0000300a -[MainCategoriesViewController viewDidLoad] + 1194
14 UIKit 0x003d1318 -[UIViewController loadViewIfRequired] + 696
15 UIKit 0x003f6b15 -[UINavigationController _layoutViewController:] + 39
16 UIKit 0x003f702b -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 235
17 UIKit 0x003f7123 -[UINavigationController _startTransition:fromViewController:toViewController:] + 78
18 UIKit 0x003f809c -[UINavigationController _startDeferredTransitionIfNeeded:] + 645
19 UIKit 0x003f8cb9 -[UINavigationController __viewWillLayoutSubviews] + 57
20 UIKit 0x00532181 -[UILayoutContainerView layoutSubviews] + 213
21 UIKit 0x00328267 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
22 libobjc.A.dylib 0x01ad081f -[NSObject performSelector:withObject:] + 70
23 QuartzCore 0x001972ea -[CALayer layoutSublayers] + 148
24 QuartzCore 0x0018b0d4 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
25 QuartzCore 0x00197235 -[CALayer layoutIfNeeded] + 160
26 UIKit 0x003e3613 -[UIViewController window:setupWithInterfaceOrientation:] + 304
27 UIKit 0x00302177 -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:isRotating:] + 5212
28 UIKit 0x00300d16 -[UIWindow _setRotatableClient:toOrientation:updateStatusBar:duration:force:] + 82
29 UIKit 0x00300be8 -[UIWindow _setRotatableViewOrientation:updateStatusBar:duration:force:] + 117
30 UIKit 0x00300c70 -[UIWindow _setRotatableViewOrientation:duration:force:] + 67
31 UIKit 0x002ffd0a __57-[UIWindow _updateToInterfaceOrientation:duration:force:]_block_invoke + 120
32 UIKit 0x002ffc6c -[UIWindow _updateToInterfaceOrientation:duration:force:] + 400
33 UIKit 0x003009c3 -[UIWindow setAutorotates:forceUpdateInterfaceOrientation:] + 870
34 UIKit 0x00303fb6 -[UIWindow setDelegate:] + 449
35 UIKit 0x003d5737 -[UIViewController _tryBecomeRootViewControllerInWindow:] + 180
36 UIKit 0x002f9c1c -[UIWindow addRootViewControllerViewIfPossible] + 609
37 UIKit 0x002f9d97 -[UIWindow _setHidden:forced:] + 312
38 UIKit 0x002fa02d -[UIWindow _orderFrontWithoutMakingKey] + 49
39 UIKit 0x0030489a -[UIWindow makeKeyAndVisible] + 65
40 UIKit 0x002b7cd0 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1851
41 UIKit 0x002bc3a8 -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 824
42 UIKit 0x002d087c -[UIApplication handleEvent:withNewEvent:] + 3447
43 UIKit 0x002d0de9 -[UIApplication sendEvent:] + 85
44 UIKit 0x002be025 _UIApplicationHandleEvent + 736
45 GraphicsServices 0x035202f6 _PurpleEventCallback + 776
46 GraphicsServices 0x0351fe01 PurpleEventCallback + 46
47 CoreFoundation 0x01e4ad65 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 53
48 CoreFoundation 0x01e4aa9b __CFRunLoopDoSource1 + 523
49 CoreFoundation 0x01e7577c __CFRunLoopRun + 2156
50 CoreFoundation 0x01e74ac3 CFRunLoopRunSpecific + 467
51 CoreFoundation 0x01e748db CFRunLoopRunInMode + 123
52 UIKit 0x002bbadd -[UIApplication _run] + 840
53 UIKit 0x002bdd3b UIApplicationMain + 1225
54 NetIncome 0x000027ad main + 141
55 libdyld.dylib 0x031c070d start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
EDIT2: And this is the original error message, only shown once and immediately after deleting the relevant files:
2014-01-28 12:00:15.598 NetIncome[2872:70b] -[__NSCFNumber getLocalizedCurrencyString]: unrecognized selector sent to instance 0x8c59720
2014-01-28 12:00:15.602 NetIncome[2872:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber getLocalizedCurrencyString]: unrecognized selector sent to instance 0x8c59720'
*** First throw call stack:
(
0 CoreFoundation 0x01ecf5e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x01abe8b6 objc_exception_throw + 44
2 CoreFoundation 0x01f6c903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x01ebf90b ___forwarding___ + 1019
4 CoreFoundation 0x01ebf4ee _CF_forwarding_prep_0 + 14
5 NetIncome 0x000358da -[NetIncomeViewController viewDidLoad] + 954
6 UIKit 0x003d1318 -[UIViewController loadViewIfRequired] + 696
7 UIKit 0x003f6b15 -[UINavigationController _layoutViewController:] + 39
8 UIKit 0x003f702b -[UINavigationController _updateScrollViewFromViewController:toViewController:] + 235
9 UIKit 0x003f7123 -[UINavigationController _startTransition:fromViewController:toViewController:] + 78
10 UIKit 0x003f809c -[UINavigationController _startDeferredTransitionIfNeeded:] + 645
11 UIKit 0x003f8cb9 -[UINavigationController __viewWillLayoutSubviews] + 57
12 UIKit 0x00532181 -[UILayoutContainerView layoutSubviews] + 213
13 UIKit 0x00328267 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
14 libobjc.A.dylib 0x01ad081f -[NSObject performSelector:withObject:] + 70
15 QuartzCore 0x001972ea -[CALayer layoutSublayers] + 148
16 QuartzCore 0x0018b0d4 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
17 QuartzCore 0x0018af40 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
18 QuartzCore 0x000f2ae6 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
19 QuartzCore 0x000f3e71 _ZN2CA11Transaction6commitEv + 393
20 QuartzCore 0x001b0430 +[CATransaction flush] + 52
21 UIKit 0x002d9dc9 _afterCACommitHandler + 131
22 CoreFoundation 0x01e974ce __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
23 CoreFoundation 0x01e9741f __CFRunLoopDoObservers + 399
24 CoreFoundation 0x01e75344 __CFRunLoopRun + 1076
25 CoreFoundation 0x01e74ac3 CFRunLoopRunSpecific + 467
26 CoreFoundation 0x01e748db CFRunLoopRunInMode + 123
27 GraphicsServices 0x0351e9e2 GSEventRunModal + 192
28 GraphicsServices 0x0351e809 GSEventRun + 104
29 UIKit 0x002bdd3b UIApplicationMain + 1225
30 NetIncome 0x00002b3d main + 141
31 libdyld.dylib 0x031c070d start + 1
32 ??? 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
The lines of code my app crashes the first time (the last line is the one):
//Get or set and get the gross income
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDecimalNumber *grossIncome = [defaults objectForKey:#"grossincome"];
if (!grossIncome) {
[defaults setObject:[NSDecimalNumber zero] forKey:#"grossincome"];
[defaults synchronize];
grossIncome = (NSDecimalNumber *)[defaults objectForKey:#"grossincome"];
}
self.incomeValueTextField.enabled = NO;
self.incomeValueTextField.delegate = self;
self.incomeValueTextField.keyboardType = UIKeyboardTypeDecimalPad;
self.incomeValueTextField.text = [grossIncome getLocalizedCurrencyString];
And my complete category:
#import "NSDecimalNumber+Currency.h"
#import "Singletons.h"
#implementation NSDecimalNumber (Currency)
- (NSString *) getLocalizedCurrencyString
{
NSNumberFormatter *numberFormatter = [[Singletons sharedManager] numberFormatter];
NSString *numberString = [numberFormatter stringFromNumber:self];
return numberString;
}
- (NSString *) getLocalizedCurrencyStringWithDigits:(int)digits
{
if(digits == 2){
return [self getLocalizedCurrencyString];
}
NSNumberFormatter *numberFormatter;
if (digits == 0){
numberFormatter =[[Singletons sharedManager] numberFormatterNoDigits];
} else {
numberFormatter =[[NSNumberFormatter alloc] init];
[numberFormatter setNumberStyle:NSNumberFormatterDecimalStyle];
[numberFormatter setLocale:[NSLocale currentLocale]];
[numberFormatter setMinimumFractionDigits:digits];
[numberFormatter setMaximumFractionDigits:digits];
}
NSString *numberString = [numberFormatter stringFromNumber:self];
return numberString;
}
+ (NSDecimalNumber *) getUnLocalizedDecimalNumberWithString:(NSString *)currencyString
{
NSNumberFormatter *numberFormatter = [[Singletons sharedManager] numberFormatter];
NSNumber *formatedCurrency = [numberFormatter numberFromString:currencyString];
BOOL isDecimal = formatedCurrency != nil;
if(isDecimal){
return [NSDecimalNumber decimalNumberWithDecimal:[formatedCurrency decimalValue]];
} else {
return [NSDecimalNumber zero];
}
}
- (NSDecimalNumber *)abs {
if ([self compare:[NSDecimalNumber zero]] == NSOrderedAscending) {
// Number is negative. Multiply by -1
NSDecimalNumber * negativeOne = [NSDecimalNumber decimalNumberWithMantissa:1
exponent:0
isNegative:YES];
return [self decimalNumberByMultiplyingBy:negativeOne];
} else {
return self;
}
}
Yesterday you have been warned about subclassing/categories on class clusters, now you see why. (Okay, actually it's more or a problem with unexpected behaviour of NSUserDefaults, but it's related ^^)
Your problem is that the object you get from NSUserDefaults is not a NSDecimalNumber, because NSDecimalNumbers are not plist values that can be saved in NSUserDefaults. But NSDecimalNumber is a subclass of NSNumber, which can be saved in NSUserDefaults, so NSUserDefaults will only save the "NSNumber part" of the NSDecimalNumber, basically it converts it to a NSNumber. Through this process it loses its precision and it's class.
When you get the object from NSUserDefaults you will actually get an instance of NSNumber. And your category does not exist on NSNumber.
I added some debug log to your code and ran it for you:
// Wrong!
NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:#"1.23456789123456789"];
NSLog(#"%# - %#", decimalNumber, NSStringFromClass([decimalNumber class]));
[[NSUserDefaults standardUserDefaults] setObject:decimalNumber forKey:#"___number"];
NSDecimalNumber *objectFromUserDefaults = [[NSUserDefaults standardUserDefaults] objectForKey:#"___number"];
NSLog(#"%# - %#", objectFromUserDefaults, NSStringFromClass([objectFromUserDefaults class]));
Which yields this result:
xxx[98912:70b] 1.23456789123456789 - NSDecimalNumber
xxx[98912:70b] 1.234567891234568 - __NSCFNumber
As you can see the returned object is an instance of __NSCFNumber
Here is the correct way:
// Correct
NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:#"1.23456789123456789"];
NSLog(#"%# - %#", decimalNumber, NSStringFromClass([decimalNumber class]));
NSData *archivedDecimalNumber = [NSKeyedArchiver archivedDataWithRootObject:decimalNumber];
[[NSUserDefaults standardUserDefaults] setObject:archivedDecimalNumber forKey:#"___archivedNumber"];
NSData *dataFromUserDefaults = [[NSUserDefaults standardUserDefaults] objectForKey:#"___archivedNumber"];
NSDecimalNumber *decimalNumberFromUserDefaults = [NSKeyedUnarchiver unarchiveObjectWithData:dataFromUserDefaults];
NSLog(#"%# - %#", decimalNumberFromUserDefaults, NSStringFromClass([decimalNumberFromUserDefaults class]));
which yields:
xxx[98912:70b] 1.23456789123456789 - NSDecimalNumber
xxx[98912:70b] 1.23456789123456789 - NSDecimalNumber
as expected.
BUT you should still get rid of that NSDecimalNumber category. Just put that code into it's own class. Call it ZHNumberFormatter and do your formatting in there.
NSNumberFormatters take their time during creation, you don't want to create them for every single conversion.
Reset your simulator and try to run the app.
iOS Simulator --> Reset content and settings.
User NSKeyedArchiver and NSKeyedUnarchiver to store the object in user defaults.
Try to use below code its working fine.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDecimalNumber *grossIncome = [defaults objectForKey:#"grossincome"];
if (!grossIncome) {
NSDecimalNumber *decNum = [[NSDecimalNumber alloc] initWithDouble:0.0f];
NSData *myEncodedObject = [NSKeyedArchiver archivedDataWithRootObject:decNum];
[defaults setObject:myEncodedObject forKey:#"grossincome"];
[defaults synchronize];
NSData *myDecodedObject = [defaults objectForKey:#"grossincome"];
grossIncome = (NSDecimalNumber*)[NSKeyedUnarchiver unarchiveObjectWithData:myDecodedObject];
}
[grossIncome getLocalizedCurrencyString];
You probably still refer to the category somewhere.
You should create an exception Breakpoint. (look for "create exception Breakpoint" in the help menu)
This will stop you on the guilty line of code!