I have a custom class oject that I want to save using NSUserDefaults, this is how I saving it:
Shift.m
-(void)encodeWithCoder:(NSCoder*)encoder
{
[encoder encodeObject:self.date forKey:#"date"];
[encoder encodeObject:self.startTime forKey:#"startTime"];
[encoder encodeObject:self.endTime forKey:#"endTime"];
}
- (id)initWithCoder:(NSCoder *)decoder {
if(self = [super init]) {
self.date = [decoder decodeObjectForKey:#"date"];
self.startTime = [decoder decodeObjectForKey:#"startTime"];
self.endTime = [decoder decodeObjectForKey:#"endTime"];
}
return self;
}
MyTableViewController.m:
-(void)saveCustomObject:(id)object forKey:(NSString*)key
{
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
[[NSUserDefaults standardUserDefaults] setObject:encodedObject forKey:key];
}
-(NSArray*)getCustomObjectForKey:(NSString*)key
{
NSData *encodedObject = [[NSUserDefaults standardUserDefaults] objectForKey:key];
NSArray *shifts=[NSArray arrayWithObjects:[NSKeyedUnarchiver unarchiveObjectWithData:encodedObject], nil];
return shifts;
}
It seems it works fine when debugging, but when I try to access one of the object properties, for example on tableView: cellForRowAtIndexPath: like that:
Shift *currentShift=[self.shifts objectForIndex:indexPath.row];
NSLog(#"%#",currentShift.startTime.description);
It crashes with that crash message:
2016-03-19 09:04:05.913 MyApp[9654:4249448] -[__NSArrayM startTime]: unrecognized selector sent to instance 0x7ff81b449c10
2016-03-19 09:04:05.924 MyApp[9654:4249448] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM startTime]: unrecognized selector sent to instance 0x7ff81b449c10'
*** First throw call stack:
(
0 CoreFoundation 0x000000010e3e9e65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010de62deb objc_exception_throw + 48
2 CoreFoundation 0x000000010e3f248d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x000000010e33f90a ___forwarding___ + 970
4 CoreFoundation 0x000000010e33f4b8 _CF_forwarding_prep_0 + 120
5 Mehuyavut count 0x000000010d95a8e8 -[shiftsTableViewViewController tableView:cellForRowAtIndexPath:] + 600
6 UIKit 0x000000010e8efe43 -[UITableView _createPreparedCellForGlobalRow:withIndexPath:willDisplay:] + 766
7 UIKit 0x000000010e8eff7b -[UITableView _createPreparedCellForGlobalRow:willDisplay:] + 74
8 UIKit 0x000000010e8c4a39 -[UITableView _updateVisibleCellsNow:isRecursive:] + 2996
9 UIKit 0x000000010e8f901c -[UITableView _performWithCachedTraitCollection:] + 92
10 UIKit 0x000000010e8dfedc -[UITableView layoutSubviews] + 224
11 UIKit 0x000000010e84d4a3 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 703
12 QuartzCore 0x000000011231959a -[CALayer layoutSublayers] + 146
13 QuartzCore 0x000000011230de70 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 366
14 QuartzCore 0x000000011230dcee _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
15 QuartzCore 0x0000000112302475 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 277
16 QuartzCore 0x000000011232fc0a _ZN2CA11Transaction6commitEv + 486
17 QuartzCore 0x000000011233037c _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
18 CoreFoundation 0x000000010e315367 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 23
19 CoreFoundation 0x000000010e3152d7 __CFRunLoopDoObservers + 391
20 CoreFoundation 0x000000010e30af2b __CFRunLoopRun + 1147
21 CoreFoundation 0x000000010e30a828 CFRunLoopRunSpecific + 488
22 GraphicsServices 0x0000000111ba6ad2 GSEventRunModal + 161
23 UIKit 0x000000010e796610 UIApplicationMain + 171
24 Mehuyavut count 0x000000010d95b5af main + 111
25 libdyld.dylib 0x0000000110b2592d start + 1
26 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
Any one knows why?
Thank you!
It seems like you want Shift *currentShift=[self.shifts objectForIndex:indexPath.row] to give you 1 Shift object, but what it really does is returning a NSArray. You basically call a startTime method in NSArray, and since it doesn't exist, your program fails.
It seems like NSLog(#"%#",currentShift.startTime.description) is the line doing that. Confirm by commenting out the NSLog. It shouldn't give you a crash.
If this hypothesis is fine, check if [currentShift isKindOfClass:[NSArray class]] is true.
If it is, a bug you have in this line:
NSArray *shifts=[NSArray arrayWithObjects:[NSKeyedUnarchiver unarchiveObjectWithData:encodedObject], nil];
You also don't really show how your - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section looks like. You must return proper number of entries there.
You're making self.shifts be an NSArray, but you use objectForKey, which is available for dictionaries. It's not available for arrays. I think you wanted objectAtIndex instead.
Related
Here's my code,
for (int i=0; i<=[selfLinksArray count]; i++) {
NSString *temp = selfLinksArray[i];
NSURL *tempURL = [NSURL URLWithString:temp ];
NSLog(#"NSURL:%#",tempURL);
NSData *tempData = [NSData dataWithContentsOfURL:tempURL];
NSError *error = nil;
NSDictionary *tempDict = [NSJSONSerialization JSONObjectWithData:tempData options:0 error:&error];
NSDictionary *volumeInfoDict = [tempDict objectForKey:#"volumeInfo"];
titleArray[i]=[volumeInfoDict objectForKey:#"title"];
}
Xcode shows me this error
[__NSArrayI length]: unrecognized selector sent to instance 0x7fdf334f0bc0
2016-01-19 16:12:34.937 BookFindr[7775:449799] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI length]: unrecognized selector sent to instance 0x7fdf334f0bc0'
*** First throw call stack:
(
0 CoreFoundation 0x000000010f34be65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010edc4deb objc_exception_throw + 48
2 CoreFoundation 0x000000010f35448d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
3 CoreFoundation 0x000000010f2a190a ___forwarding___ + 970
4 CoreFoundation 0x000000010f2a14b8 _CF_forwarding_prep_0 + 120
5 CoreFoundation 0x000000010f32e261 _CFURLCreateWithURLString + 81
6 Foundation 0x000000010e97a465 -[NSURL(NSURL) initWithString:relativeToURL:] + 349
7 Foundation 0x000000010e97a2e2 +[NSURL(NSURL) URLWithString:relativeToURL:] + 59
8 BookFindr 0x000000010e8bf9ab -[tabResTableViewController viewDidLoad] + 219
9 UIKit 0x000000010f88ef98 -[UIViewController loadViewIfRequired] + 1198
10 UIKit 0x000000010f894f4f -[UIViewController __viewWillAppear:] + 120
11 UIKit 0x000000010f8c4e44 -[UINavigationController _startCustomTransition:] + 1203
12 UIKit 0x000000010f8d523f -[UINavigationController _startDeferredTransitionIfNeeded:] + 712
13 UIKit 0x000000010f8d63af -[UINavigationController __viewWillLayoutSubviews] + 57
14 UIKit 0x000000010fa7cff7 -[UILayoutContainerView layoutSubviews] + 248
15 UIKit 0x000000010f7af4a3 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 703
16 QuartzCore 0x000000011327b59a -[CALayer layoutSublayers] + 146
17 QuartzCore 0x000000011326fe70 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 366
18 QuartzCore 0x000000011326fcee _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 24
19 QuartzCore 0x0000000113264475 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 277
20 QuartzCore 0x0000000113291c0a _ZN2CA11Transaction6commitEv + 486
21 UIKit 0x000000010f6f2f7c _UIApplicationHandleEventQueue + 7329
22 CoreFoundation 0x000000010f277a31 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
23 CoreFoundation 0x000000010f26d95c __CFRunLoopDoSources0 + 556
24 CoreFoundation 0x000000010f26ce13 __CFRunLoopRun + 867
25 CoreFoundation 0x000000010f26c828 CFRunLoopRunSpecific + 488
26 GraphicsServices 0x0000000112b08ad2 GSEventRunModal + 161
27 UIKit 0x000000010f6f8610 UIApplicationMain + 171
28 BookFindr 0x000000010e8c101f main + 111
29 libdyld.dylib 0x0000000111a8792d start + 1
30 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
I have imported selfLinkArray from another viewController. I want to fetch various titles which are present in VolumeInfo dictionary. This dictionary is present in each individual link in selfLinksArray. Please help me with this error. Thanks in Advance.
Let's analyze your error and your backtrace :
-[__NSArrayI length]: unrecognized selector sent to instance 0x7fdf334f0bc0'
The issue is written here: the length method is called on an NSArray object.
Wait, this method is not even written in this sample! Don't worry, let's analyze it.
6 Foundation 0x000000010e97a465
-[NSURL(NSURL) initWithString:relativeToURL:] + 349
7 Foundation 0x000000010e97a2e2 +[NSURL(NSURL) URLWithString:relativeToURL:]
The crash log indicates that the crash occurs when you try to init the NSURL object. The only parameter of this init method is a NSString object. But are we sure that temp is really a NSString object ?
This variable is casted without checking if it's really an NSString object. It can be anthing, for example... the NSArray which receive a call to the length method. Also, this method is existing for a NSString object, so the unrecognizer selector error look totally related.
Where do you we call length on this NSString object ? My guess is, according to the backtrace, that URLWithString: call this method to check the NSString length in order to initialize properly the NSURL object.
I have a NSDictionary that I add to a mutable array but when I try add the array to populate a uitableview I get an error.
NSMutableArray *array = [[NSMutableArray alloc] init];
for (id element in self.categoriesMutableNameArray) {
[array addObject:#"No"];
}
self.categoryDict = #{ #"title" : self.categoriesMutableNameArray, #"selected" : array};
self.categoryArr = [[NSMutableArray alloc] init];
self.categoryMutableDict = [NSMutableDictionary dictionaryWithDictionary:self.categoryDict];
[self.categoryArr addObject:self.categoryDict];
and the following categoryArr is printed like this:
2014-02-27 15:09:07.397 App[7982:70b] (
{
selected = (
No,
No,
No,
No,
No,
No,
No,
No,
No,
No,
No,
No,
No,
No
);
title = (
"Fashion - Women",
"Fashion - Men",
Kids,
"Accessories - Women",
"Accessories - Men",
"Styling / Hair",
Inspiration,
"Decoration / Architecture",
"Great Places",
"Art / Design",
"Music / Movie / Books",
"Food / Drink",
"Gadgets / Tech",
Rides
);
}
)
The trouble I am having is in the uitableview cellforrowatindexpath method I try and add the title key for the categoryArr to populate the uitableview and I get the following error on this line:
UILabel *categoryLabel = (UILabel *)[cell viewWithTag:111];
categoryLabel.text = [NSString stringWithFormat:#"%#",[[self.categoryArr objectAtIndex:indexPath.row] objectForKey:#"title"];
And the error log:
2014-02-27 15:24:33.804 App[8153:70b] -[__NSArrayM length]: unrecognized selector sent to instance 0xa9bc3a0
2014-02-27 15:24:33.807 App[8153:70b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM length]: unrecognized selector sent to instance 0xa9bc3a0'
*** First throw call stack:
(
0 CoreFoundation 0x020c75e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x01e4a8b6 objc_exception_throw + 44
2 CoreFoundation 0x02164903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x020b790b ___forwarding___ + 1019
4 CoreFoundation 0x020b74ee _CF_forwarding_prep_0 + 14
5 Foundation 0x006e18ed -[NSConcreteMutableAttributedString replaceCharactersInRange:withString:] + 39
6 Foundation 0x006e255a -[NSConcreteMutableAttributedString initWithString:attributes:] + 293
7 UIKit 0x01172bc6 -[UILabel _setText:] + 97
8 UIKit 0x01172d84 -[UILabel setText:] + 40
9 App 0x00047ebd -[PiccImageCategoriesViewController tableView:cellForRowAtIndexPath:] + 1533
10 UIKit 0x010b461f -[UITableView _createPreparedCellForGlobalRow:withIndexPath:] + 412
11 UIKit 0x010b46f3 -[UITableView _createPreparedCellForGlobalRow:] + 69
12 UIKit 0x01098774 -[UITableView _updateVisibleCellsNow:] + 2378
13 UIKit 0x010abe95 -[UITableView layoutSubviews] + 213
14 UIKit 0x01030267 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
15 libobjc.A.dylib 0x01e5c81f -[NSObject performSelector:withObject:] + 70
16 QuartzCore 0x00c8e2ea -[CALayer layoutSublayers] + 148
17 QuartzCore 0x00c820d4 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
18 QuartzCore 0x00c81f40 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
19 QuartzCore 0x00be9ae6 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
20 QuartzCore 0x00beae71 _ZN2CA11Transaction6commitEv + 393
21 QuartzCore 0x00beb544 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
22 CoreFoundation 0x0208f4ce __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
23 CoreFoundation 0x0208f41f __CFRunLoopDoObservers + 399
24 CoreFoundation 0x0206d344 __CFRunLoopRun + 1076
25 CoreFoundation 0x0206cac3 CFRunLoopRunSpecific + 467
26 CoreFoundation 0x0206c8db CFRunLoopRunInMode + 123
27 GraphicsServices 0x027779e2 GSEventRunModal + 192
28 GraphicsServices 0x02777809 GSEventRun + 104
29 UIKit 0x00fc5d3b UIApplicationMain + 1225
30 App 0x0001406d main + 141
31 libdyld.dylib 0x02f4d70d start + 1
32 ??? 0x00000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
Thanks
The return of [[self.categoryArr objectAtIndex:indexPath.row] objectForKey:#"title"]; is a array of NSString, categoryLabel.text = [NSString stringWithFormat:#"%#", /*the return array*/]; this is the problem.
Maybe what you want is:
NSArray *categoryDetailArr = [[self.categoryArr objectAtIndex:indexPath.section] objectForKey:#"title"];
categoryLabel.text = [[categoryDetailArr objectAtIndex:indexPath.row];
Write this code
categoryLabel.text = [[[self.categoryArr objectAtIndex:0] objectForKey:#"title"]objectAtIndex:indexPath.row];
instead OF
categoryLabel.text = [NSString stringWithFormat:#"%#",[[self.categoryArr objectAtIndex:indexPath.row] objectForKey:#"title"];
And plz check that in UITableView dataSource methods i.e
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [categoryLabel objectAtIndex:0]valueForKey:#"selected"].count;
}
OR
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [categoryLabel objectAtIndex:0]valueForKey:#"title"].count;
}
I have an iPhone app which fetches user information (first name, last name, city) in JSON format from different social networks.
This works mostly well, but one of the social networks returns the city as a number instead of a string (actually I should made one more REST call to map this number to a city name... but for now I just want to display the number).
And when I try to display that number in a UILabel I get the exception (here fullscreen):
2014-02-15 11:24:16.194 MyAuth[8872:a0b] -[__NSCFNumber length]: unrecognized selector sent to instance 0xb074f90
2014-02-15 11:24:16.203 MyAuth[8872:a0b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFNumber length]: unrecognized selector sent to instance 0xb074f90'
*** First throw call stack:
(
0 CoreFoundation 0x01bb15e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x019348b6 objc_exception_throw + 44
2 CoreFoundation 0x01c4e903 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275
3 CoreFoundation 0x01ba190b ___forwarding___ + 1019
4 CoreFoundation 0x01ba14ee _CF_forwarding_prep_0 + 14
5 Foundation 0x015798ed -[NSConcreteMutableAttributedString replaceCharactersInRange:withString:] + 39
6 Foundation 0x0157a55a -[NSConcreteMutableAttributedString initWithString:attributes:] + 293
7 UIKit 0x0084fbc6 -[UILabel _setText:] + 97
8 UIKit 0x0084fd84 -[UILabel setText:] + 40
9 MyAuth 0x0000a296 -[UserViewController viewDidLoad] + 678
10 UIKit 0x007b6318 -[UIViewController loadViewIfRequired] + 696
11 UIKit 0x007b65b4 -[UIViewController view] + 35
12 UIKit 0x007d03e2 -[UINavigationController _startCustomTransition:] + 778
13 UIKit 0x007dd0c7 -[UINavigationController _startDeferredTransitionIfNeeded:] + 688
14 UIKit 0x007ddcb9 -[UINavigationController __viewWillLayoutSubviews] + 57
15 UIKit 0x00917181 -[UILayoutContainerView layoutSubviews] + 213
16 UIKit 0x0070d267 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 355
17 libobjc.A.dylib 0x0194681f -[NSObject performSelector:withObject:] + 70
18 QuartzCore 0x054e12ea -[CALayer layoutSublayers] + 148
19 QuartzCore 0x054d50d4 _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 380
20 QuartzCore 0x054d4f40 _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 26
21 QuartzCore 0x0543cae6 _ZN2CA7Context18commit_transactionEPNS_11TransactionE + 294
22 QuartzCore 0x0543de71 _ZN2CA11Transaction6commitEv + 393
23 QuartzCore 0x0543e544 _ZN2CA11Transaction17observer_callbackEP19__CFRunLoopObservermPv + 92
24 CoreFoundation 0x01b794ce __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 30
25 CoreFoundation 0x01b7941f __CFRunLoopDoObservers + 399
26 CoreFoundation 0x01b57344 __CFRunLoopRun + 1076
27 CoreFoundation 0x01b56ac3 CFRunLoopRunSpecific + 467
28 CoreFoundation 0x01b568db CFRunLoopRunInMode + 123
29 GraphicsServices 0x031a09e2 GSEventRunModal + 192
30 GraphicsServices 0x031a0809 GSEventRun + 104
31 UIKit 0x006a2d3b UIApplicationMain + 1225
32 MyAuth 0x0000ab7d main + 141
33 libdyld.dylib 0x02518725 start + 0
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)
So I go to my JSON parsing code:
- (User*)createUserFromJson:(id)json
{
if (![json isKindOfClass:[NSDictionary class]]) {
NSLog(#"Parsing response failed");
return nil;
}
NSDictionary *dict = json[#"response"][0];
User *user = [[User alloc] init];
user.key = kVK;
user.userId = dict[#"uid"];
user.firstName = dict[#"first_name"];
user.lastName = dict[#"last_name"];
user.city = dict[#"city"]; // THE PROBLEMATIC LINE
user.avatar = dict[#"photo_big"];
user.female = (2 == [dict[#"female"] intValue]);
return user;
}
and try to change it to:
user.city = [NSString stringWithFormat:#"%d", dict[#"city"]];
but then I get the compile-time warning (here fullscreen):
Format specifies type 'int' but the argument has type 'id'
So my question is how to solve this issue cleanly (w/o Xcode warnings) and robust (when fetched JSON data happens to be a string)?
The fastest solution is:
[NSString stringWithFormat:#"%#", dict[#"city"]];
which will take the description of the string or the number and convert that into a string.
In the future you may want to use:
if ([1dict[#"city"] isKindOfClass:[NSNumber class]]) { ...
to check what you have received and work with it specifically. i.e. to do your lookup and to not use stringWithFormat: when you actually already have a string (because it's inefficient).
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!
I get this exception in my Crashalytics:
0 CoreFoundation
__exceptionPreprocess + 162
1 libobjc.A.dylib
objc_exception_throw + 30
2 CoreFoundation
-[NSException initWithCoder:]
3 CoreFoundation
-[__NSCFArray objectAtIndex:] + 136
4 BusinessPlan ✭ BusinessController.m line 167
-[BusinessController tableView:didSelectRowAtIndexPath:] + 167
5 UIKit
-[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 876
6 UIKit
-[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 156
7 Foundation
__NSFireDelayedPerform + 450
8 CoreFoundation
__CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 14
9 CoreFoundation
__CFRunLoopDoTimer + 272
10 CoreFoundation
__CFRunLoopRun + 1232
11 CoreFoundation
CFRunLoopRunSpecific + 356
12 CoreFoundation
CFRunLoopRunInMode + 104
13 GraphicsServices
GSEventRunModal + 74
14 UIKit
UIApplicationMain + 1120
15 BusinessPlan main.m line 16
main + 16
16 BusinessPlan
start
and it is called this:
Exception Type: NSRangeException
Reason: -[__NSCFArray objectAtIndex:]: index (14) beyond bounds (14)
It only happened once so I am not sure how to reproduce it. But it happened in this code:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *info = [topics_array objectAtIndex:indexPath.row];
NSString *section_name = [info objectForKey:#"section_name"];
NSString *solution_section_id = [info objectForKey:#"solution_section_id"];
// PUT THESE ITEMS INTO THE SESSION
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
[standardUserDefaults setObject:section_name forKey:#"section_name"];
[standardUserDefaults setObject:solution_section_id forKey:#"solution_section_id"];
[standardUserDefaults synchronize];
[self performSegueWithIdentifier:#"BusinessToTopic" sender:self];
}
Would anyone know how to prevent this from happening in the future and why it is happening?
EDIT:
This is the code for tableView numberOfRowsInSection
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [tableLabels count];
}
Thanks!