why iOS App terminating due to NSRangeException - ios

I'm having a weird error popping up. It's listing that my app is
Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 0 beyond bounds for empty array'
What puzzles me is that the app runs perfectly fine in the simulator, but when I go to test it on my device I get that error. I've isolated the problem to the line of code below:
updatingTracker = [userDatas objectAtIndex:repeatCount];
Here is the rest of the relevant code:
[self getUserDatas];
[self timerDidFire];
-(void) getUserDatas
{
userDatas = [[NSMutableArray alloc] init];
NSUserDefaults *userdef = [NSUserDefaults standardUserDefaults];
int count = [[userdef objectForKey:#"user_count"] intValue];
for(int i=0;i<count;i++)
{
NewTracker *newtrack=[[NewTracker alloc] init];
newtrack.FromCurrency = [userdef objectForKey:[NSString stringWithFormat:#"from_string_%d",i]];
newtrack.ToCurrency = [userdef objectForKey:[NSString stringWithFormat:#"to_string_%d",i]];
newtrack.savedCurrency = [userdef objectForKey:[NSString stringWithFormat:#"save_currency_%d",i]];
newtrack.userTarget = [userdef objectForKey:[NSString stringWithFormat:#"user_target_%d",i]];
newtrack.trackerId = [userdef objectForKey:[NSString stringWithFormat:#"tracker_id_%d",i]];
newtrack.realtimeBase = [userdef objectForKey:[NSString stringWithFormat:#"realtime_base_%d",i]];
newtrack.realtimeTarget = [userdef objectForKey:[NSString stringWithFormat:#"realtime_target_%d",i]];
newtrack.realtimeUSD = [userdef objectForKey:[NSString stringWithFormat:#"realtime_USD_%d",i]];
[userDatas addObject:newtrack];
}
}
- (void) timerDidFire
{
NSLog(#"bug finder");
updatingTracker = [userDatas objectAtIndex:repeatCount];
[self chartconnectionStart:#"3m"];
}
Any ideas or help on why this is happening or how to fix it would be appreciated.

Your userDatas array is empty. You most likely don't have anything populated in your user defaults on your phone, so the code that adds to the array is never executed. You probably have some data already populated on your simulator and that's why it's not working on the phone

Simple put a conditional breakpoint on that line for the condition [userDatas count] == 0. Or put in an if to catch that and a breakpoint on it. They use the debugger to figure out how you got there and what the associated values are.
Basic debugging.

Code like this
(void) timerDidFire{
NSLog(#"bug finder");
if([userDatas count]>0){
updatingTracker = [userDatas objectAtIndex:repeatCount];
[self chartconnectionStart:#"3m"];
}
}
Happy coding..........

Related

How to see if a NSUserdefaults is nil or not?

Well I dont know if my title is well drafted but I will try to explain whats my problem, I want to save a NSDate for an IndexPath in NSUserDefaults, this happens when viewWillDisappear but its crashing, its saving correctly because when I reopen the DatePicker loads the date I want but still crash when saving a date at the UserDefaults
So heres my code so you can see whats going on....
I read if the NSUserDefaults is nil or not so I can load the DatePicker:
NSArray *indexParams = [self.userdefaults objectForKey:#"indexpath"];
NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:indexParams[1]
inSection:indexParams[0]];
self.notificationDate = [self.userdefaults objectForKey:#"date"];
NSDate *date = [self.userdefaults objectForKey:[NSString stringWithFormat:#"%d", myIndexPath.row]];
if(date){
[self.NotSwith setOn:YES];
self.DatePicker.date = [self.userdefaults objectForKey:[NSString stringWithFormat:#"%d", myIndexPath.row]];
}else{
[self.NotSwith setOn:NO];
}
When I want to save the date in viewWillDisappear its when the crash happens:
NSArray *indexParams = [self.userdefaults objectForKey:#"indexpath"];
NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:indexParams[1]
inSection:indexParams[0]];
NSDate *date = [self.userdefaults objectForKey:[NSString stringWithFormat:#"%d", myIndexPath.row]];
if(date){
// [self.userdefaults synchronize];
}
else{
[self.userdefaults setObject:self.DatePicker.date forKey:[NSString stringWithFormat:#"%d", myIndexPath.row]];
[self.userdefaults synchronize];
[[UIApplication sharedApplication] scheduleLocalNotification:local];
}
But the info its saved successfully and the date picker loads the date in relaunch.
crash log:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'
So hope I explained well, Thanks!
Setting the indexpath:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
NSNumber *section = [NSNumber numberWithInt:indexPath.section];
NSNumber *rows = [NSNumber numberWithInt:indexPath.row];
[self.userdefaults setObject:#[section, rows] forKey:#"indexpath"];
}
Sounds like you want to save both the selected index path and a date. Saving a date in NSUserDefaults is easy.
// no need to keep a property on self for user defaults. you don't need to keep
// that around. just a stack variable will work.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDate *date = [NSDate date];
[defaults setObject:date forKey:#"myDate"];
[defaults synchronize];
Get it back later on this way:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDate *date = [defaults objectForKey:#"myDate"];
// if nothing has been stored using that key then objectForKey will return nil
if (date) {
// it's there!
} else {
// it's not there
}
Storing an index path is a little more tricky, but this will work:
// wrap your row and section in NSNumbers, wrap those in an array for brevity
NSNumber *section = [NSNumber numberWithInt:myIndexPath.section];
NSNumber *row = [NSNumber numberWithInt:myIndexPath.row];
[defaults setObject:#[section, row] forKey:#"myIndexPath"]; // then synchronize
// naturally, when you get it later, you can check for nil again, and,
// if it's not nil, to rebuild the index path...
NSArray *indexParams = [defaults objectForKey:#"myIndexPath"];
NSIndexPath *myIndexPath = [NSIndexPath indexPathForRow:indexParams[1]
inSection:indexParams[0]];
The key is what isn't in this answer: no NSData, no NSKeyedArchiver, no string manipulation to build an index path representation. Best of luck.

Modifying NSDictionary in run Time [duplicate]

This question already has answers here:
Mutable Objects inside NSUserDefaults
(4 answers)
Closed 9 years ago.
Please Help me.
I have a plist clothingList.plist
I am accessing it like this in a method
NSString *path=[[NSBundle mainBundle] pathForResource:#"ClothingList" ofType:#"plist"];
//NSDictionary *ClothingAssets ; //Declared globally in .h file
ClothingAssets=[[NSMutableDictionary alloc]initWithContentsOfFile:path];
[[NSUserDefaults standardUserDefaults]setObject:ClothingAssets forKey:#"ClothingAssets"];
[[NSUserDefaults standardUserDefaults] synchronize];
Now I want to modfify a bool value in Clothing Assets Dictionary in another method.
ClothingAssets=[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"ClothingAssets"];
[[[[[[ClothingAssets objectForKey:#"ClothingStore"] objectAtIndex:temp_Store]objectForKey:#"Assets" ]objectForKey:[NSString stringWithFormat:#"%#",temp_AssetType]] objectAtIndex:ii] setValue:#"YES" forKey:#"isLock"] ;
When I run the code For the first time it crashes and Show an error like this:
************ Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'***
*** First throw call stack:
(0x1fb5012 0x29c5e7e 0x1fb4deb 0x1f7b347 0x3f39bf 0x435d9 0x41f76 0xea5020 0x29d9705 0xab5920 0xab58b8 0xb76671 0xb76bcf 0xb75d38 0xae533f 0xae5552 0xac33aa 0xab4cf8 0x3397df9 0x3397ad0 0x1f2abf5 0x1f2a962 0x1f5bbb6 0x1f5af44 0x1f5ae1b 0x33967e3 0x3396668 0xab265c 0x22ed 0x2225 0x1)
libc++abi.dylib: terminate called throwing an exception******
But When I run the code for second time it is working properly.
please help me.
There are many similar questions. From the exception its evident that you are trying to include a value to an immutable dictionary.
Unwrap the values one at a time and since you are going to edit them always make a mutableCopy
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableDictionary *clothingAssets=[[defaults dictionaryForKey:#"ClothingAssets"] mutableCopy];
NSMutableArray *clothingStores = [clothingAssets[#"ClothingStore"] mutableCopy];
NSMutableDictionary *clothingStore = [clothingStores[temp_Store] mutableCopy];
NSMutableDictionary *assets = [clothingStore[#"Assets"]mutableCopy];
NSString *assetTypesKey = [NSString stringWithFormat:#"%#",temp_AssetType];
NSMutableArray *assetTypes = [assets[assetTypesKey]mutableCopy];
NSMutableDictionary *assetType = [assetTypes[i] mutableCopy];
//Value is set
assetType[#"isLock"] = #"YES";
//Now you need to update the values back to the top most level
[assetTypes replaceObjectAtIndex:i withObject:assetType];
assets[assetTypesKey] = assetTypes ;
clothingStore[#"Assets"] = assets;
[clothingStores replaceObjectAtIndex:temp_Store withObject:clothingStore];
clothingAssets[#"ClothingStore"] = clothingStores;
[defaults setObject:clothingAssets forKey:#"ClothingAssets"];
[defaults synchronize];
Nested message sends aside, this is actually rather straightforward. When you see that error, it means you're trying to mutate an immutable object. The runtime throws a tantrum when you try to do that. Instead, do this:
ClothingAssets=[[NSUserDefaults standardUserDefaults] dictionaryForKey:#"ClothingAssets"];
NSDictionary *clothingStore = [ClothingAssets objectForKey:#"ClothingStore"];
NSArray *assets = [clothingStore objectForKey:#"Assets"];
NSDictionary *subAsset = [assets objectAtIndex: temp_Store];
NSArray *subAssetArray = [subAsset objectForKey: [NSString stringWithFormat:#"%#",temp_AssetType];
// At this point I'm afraid I run out of creative ways to describe your storage hierarchy:
NSDictionary *subAssetArraySubDictionary = [subAssetArray objectAtIndex: ii];
NSMutableDictionary *mutableCopy = [subAssetArraySubDictionary mutableCopy];
// And finally, set the value:
// Beware: This uses the string YES instead of a boolean value for YES - you need to remember this
// when accessing it later.
[mutableCopy setValue: #"YES" forKey: #"isLock"];

NSArray Error: NSCFArray objectAtIndex index (5) beyond bounds (5)

I have an MutableArray filled with values from a database:
NSMutableArray *objectsArray = [[NSMutableArray alloc] init];
for (int n=0; n<[self.array count]; n++) {
[objectsArray addObject:[[self.array objectAtIndex:n] objectForKey:#"Name"]];
[objectsArray addObject:[[self.array objectAtIndex:n] objectForKey:#"Name_En"]];
}
I show the values on labels like so:
cell.textLabel.text = [[[dic objectForKey:#"d"] objectAtIndex:indexPath.row] objectForKey:#"Name"];
cell.detailTextLabel.text = [[[dic objectForKey:#"d"] objectAtIndex:indexPath.row] objectForKey:#"Name_En"];
So far the app works fine. It starts without throwing an exception and the values are in the labels. But if I start to scroll the app crashes and I get the following error:
Terminating app due to uncaught exception 'NSRangeException', reason: '-[__NSCFArray objectAtIndex:]: index (5) beyond bounds (5)'
Why is this error occurring?
You are probably saying the table that you have 6 rows, but you actually have 5. The reason for this exception is that the table view asks for cell for indexPath.row with value of 5, which means it thinks that there are 6 [0:5] rows, but your array in the dictionary has 5 items [0:5).
I was facing the same the problem which you mention earlier.
Then I did this :-
cell.TitleLabel.text=[[AllUserDataArray objectAtIndex:indexPath.row]objectAtIndex:0];
cell.DateAndTimeLabel.text=[[AllUserDataArray objectAtIndex:indexPath.row]objectAtIndex:1];
cell.InfoLabel.text=[[AllUserDataArray objectAtIndex:indexPath.row]objectAtIndex:2];
if([[AllUserDataArray objectAtIndex:indexPath.row] count] >3) {
NSData *imageData=[[AllUserDataArray objectAtIndex:indexPath.row]objectAtIndex:3];
UIImage *travelImage=[UIImage imageWithData:imageData];
cell.ImgView.image=travelImage;
It is working fine and logically correct also(I think so) :)
Hope this will help you.
I was facing the same the problem and i got the solution:
NSMutableArray *objectsArray = [[NSMutableArray alloc] init];
objectsArray=nil;
for (int n=0; n<[self.array count]; n++) {
[objectsArray addObject:[[self.array objectAtIndex:n] objectForKey:#"Name"]];
[objectsArray addObject:[[self.array objectAtIndex:n] objectForKey:#"Name_En"]];
}

objectForKey crash? iOS

I am trying to use the following code to load a UIButton and UITextField with information based upon a UISegmentedControl's current segment that is clicked but it is causing a SIGABRT crash.
Here is the code:
- (void)updateInfo {
NSLog(#"count1:%d", [self.accounts count]);
[self saveInfo];
NSLog(#"count2:%d", [self.accounts count]);
NSDictionary *dict = [self.accounts objectAtIndex:0];
NSData *imageData = [dict objectForKey:#"ProfileImage"];
UIImage *imageProfile = [UIImage imageWithData:imageData];
[image1 setImage:imageProfile];
NSDictionary *dict2 = [self.accounts objectAtIndex:1];
NSData *imageData2 = [dict2 objectForKey:#"ProfileImage"];
UIImage *imageProfile2 = [UIImage imageWithData:imageData2];
[image2 setImage:imageProfile2];
if ([self.accounts objectAtIndex:accountSC.selectedSegmentIndex] != nil) {
NSDictionary *dict = [self.accounts objectAtIndex:accountSC.selectedSegmentIndex];
//NSString *name = [dict objectForKey:#"Name"];
NSString *name = [accountSC titleForSegmentAtIndex:accountSC.selectedSegmentIndex];
[Name setText:name];
NSData *imageData = [dict objectForKey:#"ProfileImage"];
UIImage *imageProfile = [UIImage imageWithData:imageData];
[pictureButton setImage:imageProfile forState:UIControlStateNormal];
}
else {
Name.text = nil;
[pictureButton setImage:nil forState:UIControlStateNormal];
}
}
The first & second big block of code is temporary because I wanted to see the UIImage's based upon different objectAtIndex numbers.
Here is the console crash log:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFConstantString objectForKey:]: unrecognized selector sent to instance 0x2cc08'
Any reason why this can be happening? Do I need to post any other code I am using?
I really need help on this, I have been pulling my hair out!!!
Edit1:
I am using this code, also you were talking about isKindOfClass right?
Anyway this is the code:
NSDictionary *dict = [self.accounts objectAtIndex:1];
if ([dict isKindOfClass:[NSDictionary class]]) {
NSLog(#"YES");
}
else {
NSLog(#"NO");
}
Im testing now...
You're sending objectForKey: to an NSString object, specifically one that you've typed directly into your code somewhere in #"..." form rather than one you've created programmatically (or had created programmatically for you). Someone is putting something other than a dictionary into self.accounts.
NSDictionary: objectForKey:
objectForKey: returns the value associated with key, or nil if no value is associated with key.
key :A string identifying the value. If nil, just return nil.
(1)you should know the key is not blank
(2)you should know the object is not blank and the objects are the same type ,because you shouldn't use different kinds of type in a NSDictionary.
e.g. {#"key1":NSString,#"key2":NSArray} //this is a demonstration of error

Problems saving values in NSUserDefaults

I have this as my viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
if (defaults == [cells objectAtIndex:0])
{
NSString * myFile = [[NSBundle mainBundle]pathForResource:#"cells" ofType:#"plist"];
cells = [[NSMutableArray alloc]initWithContentsOfFile:myFile];
}
else
{
[defaults stringForKey:#"string1"];
}
}
And for my viewWillDisappear I have:
-(void)viewWillDisappear:(BOOL)animated
{
string1 = [cells objectAtIndex:0];
[defaults setObject:string1 forKey:#"string1"];
}
But I cannot get the data to be saved. Does anyone know what I'm doing wrong?
defaults should be an instance of NSUserDefaults:
defaults = [NSUserDefaults sharedUserDefaults];
Therefore, if (defaults == [cells objectAtIndex:0]) is not a valid line of code and it will never be equal unless you're fiddling with the RAM.
Otherwise, the code looks fine.
Are you setting defaults to [NSUserDefaults standardUserDefaults] somewhere? Also, why are you comparing it to the first object in the cells array? Seems strange.
You've otherwise got the idea correct. Make sure the viewWillDisappear method is actually getting called. Also you can call [NSUserDefaults synchronize] to save the changes immediately.
One last thing, you aren't doing anything in that else {} block. You need to assign the value of [defaults stringForKey:#"string1"]; to a variable to use it.

Resources