I am pretty new to objective c and iOS programming, and I have this pretty strange error. The app in question initializes a NSMutableArray with a preset set of values of a custom type I made using NSObject. Which is manipulated by the app. If new values are added during app run time, they are saved using NSUserDefaults, and are brought up from NSUserDefaults along with the default values on next app open.
This is the error I get:
Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFConstantString 0xb404> valueForUndefinedKey:]: this class is not key value coding-compliant for the key score.'
*** First throw call stack:
(0x1c9b012 0x10d8e7e 0x1d23fb1 0xb84d1d 0xaf100b 0xaf0fbd 0xb0f247 0xb3023c 0xb30056 0x3e40 0x3c5f 0x11f5ad 0x10ec705 0x202c0 0x20258 0x242ff4 0x10ec705 0x202c0 0x20258 0xe1021 0xe157f 0xe1056 0x246af9 0x10ec705 0x202c0 0x20258 0xe1021 0xe157f 0xe06e8 0x4fcef 0x4ff02 0x2dd4a 0x1f698 0x1bf6df9 0x1bf6ad0 0x1c10bf5 0x1c10962 0x1c41bb6 0x1c40f44 0x1c40e1b 0x1bf57e3 0x1bf5668 0x1cffc 0x290d 0x2835)
libc++abi.dylib: terminate called throwing an exception
I am not quite sure what the error is or how to go about debugging it.
Previously this code worked flawlessly, all I did was remove one or two elements from the preset default list of elements, and in the simulator, simulated deleting the app, and recompiled the code. Ever since my program crashes, with the above message, and I can't figure out how to fix it.
So if someone can give me some help on how to go about debugging this, that would be wonderful. I can attach code as needed, i'm not sure what code would be relevant to be shown, and it may be too much to post all the code involved in the project.
Code to encode and decode the properties of my custom Name NSObject class called name.h:
-(void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:self.name forKey:#"name"];
[encoder encodeInteger:self.score forKey:#"score"];
}
-(id)initWithCoder:(NSCoder *)decoder
{
if((self = [super init]))
{
self.name = [decoder decodeObjectForKey:#"name"];
self.score = [decoder decodeIntegerForKey:#"score"];
}
return self;
}
Retrieving Data from class, incase this matters, this code occurs in appdelegate.m:
NSData *data = [[NSUserDefaults standardUserDefaults] objectForKey:#"dataArray"];
NSInteger score = 0;
NSMutableArray *temp = [[NSMutableArray alloc] initWithObjects:#"name", nil];
NSMutableArray *tempList = [[NSMutableArray alloc] init];
for(NSString *y in temp)
{
Name *name = [[Name alloc] init];
name.name = y;
name.score = score;
[tempList addObject:name];
}
if (data)
{
NSArray *list = [NSKeyedUnarchiver unarchiveObjectWithData:data];
NSMutableArray *names = [[NSMutableArray alloc]initWithArray:list];
// [_nameList addObjectsFromArray:temp];
NSMutableArray *t = [[names arrayByAddingObjectsFromArray:tempList ] mutableCopy];
_nameList = [[NSMutableArray alloc]init];
[_nameList addObjectsFromArray:t];
}
else
{
//First time load or data is not saved yet
_nameList = [[NSMutableArray alloc] initWithObjects:#"name", nil];
}
saving the array at close time:
- (void)applicationWillTerminate:(UIApplication *)application
{
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
NSData *data =[NSKeyedArchiver archivedDataWithRootObject:_nameList];
[[NSUserDefaults standardUserDefaults] setObject:data forKey:#"dataArray"];
}
same code is in applicationDidEnterBackground.
code to sort by 'score'
- (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController: (UIViewController *)viewController
{
if(viewController == _viewController3)
{
[self sortNames:_nameList];
[[(ThirdViewController*)_viewController3 topList] reloadData];
}
}
-(void)sortNames:(NSMutableArray*)test
{
NSArray* temp = [[NSArray alloc] initWithArray:test];
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"score" ascending:NO];
NSArray *sortedLinks = [[temp sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]] mutableCopy];
_nameList = (NSMutableArray*) sortedLinks;
}
Here's my two cents. You have this line:
[encoder encodeObject:self.name forKey:#"name"];
And then this line:
Name *name = [[Name alloc] init];
This makes me think that the "self.name" property is one of these "Name" custom subclasses.
I believe that if you make a custom subclass and you want it to encodewithcoder, you have to add the encodewithcoder method to your custom subclass and have it encodewithcoder all of its properties and instance variables as primitively as you can.
Meaning, your Name class needs to have its own encodewithcoder method that encodes all of its properties and instance variables that have been stored as factory objects or c primitives.
Edit: I'm still pretty new and value my rep. If I'm wrong, please comment and I'll delete but please don't downvote me to oblivion
Here:
_nameList = [[NSMutableArray alloc] initWithObjects:#"name", nil];
you are adding an NSString to the _nameList array. Later you save that array.
The next time you load that array, you have the NSString #"name" in it. I guess at some point you iterate through the items in _nameList and try to get or set the score, since you are calling this on a subclass of NSString you get the NSUnknownKeyException.
I think what you want to is to replace the line above with something like this: (assuming the class in your name.h file you mentioned above is called Name)
Name *newName = [[Name alloc] init]; //or initialize the way you need to
_nameList = [[NSMutableArray alloc] initWithObjects:newName, nil];
Related
I have a button that whenever it is pressed is supposed to increment by one, which as a result will display a new string into a textfield. I have a Core Data manager class that contains a method which is supposed to retrieve my arrays, however whenever I press the button the app crashes. I'm left with an error stating ...
"Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UsefulCodes rangeOfCharacterFromSet:]: unrecognized selector sent to instance 0x6000000a3f60'"
"UsefulCodes" is the name of my Core Data entity, and "codeName" and "codeDescription" are the attributes fro my presetList and codeDescArray respectively. I think its not working because I'm trying to put a Core Data object into a textfield, but all the objects in the arrays are strings, how would I get it to pass successfully into the textfield? I'll post relevant code below.
From CoreDataManager -
#implementation CoreDataManager
+(CoreDataManager*)sharedInstance {
static CoreDataManager *sharedObject;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedObject = [[CoreDataManager alloc] init];
});
return sharedObject;
}
-(void)storeListFirstTime {
//http://morsecode.scphillips.com/morse.html
NSArray* presetList = [NSArray arrayWithObjects:#"AS",
#"BCNU",
#"CL",
#"CT",
#"CUL",
#"K",
#"QSL",
#"QSL?",
#"QRX?",
#"QRV",
#"QRV?",
#"QTH",
#"QTH?",
#"R",
#"SN",
#"SOS",
#"73",
#"88",
nil];
NSArray* codeDescArray = [NSArray arrayWithObjects:#"Wait",
#"Be seeing You",
#"Going off air",
#"Start Copying",
#"See you later",
#"Over",
#"I acknowledge receipt",
#"Do you acknowledge",
#"Should I wait",
#"Ready to copy",
#"Are you ready to copy?",
#"My location is ...",
#"What is your location?",
#"Roger",
#"Understood",
#"Distress message",
#"Best regards",
#"Love and kisses",
nil];
//Saves the initial list of items
for(int i = 0; i < presetList.count; i++) {
NSManagedObjectContext *context = [self context];
UsefulCodes *codeObj = [NSEntityDescription insertNewObjectForEntityForName:#"UsefulCodes"
inManagedObjectContext:context];
codeObj.codeName = [presetList objectAtIndex:i];
codeObj.codeDescription = [codeDescArray objectAtIndex:i];
NSLog(#"CODEOBJ: %#", codeObj);
}
[self saveContext];
}
//THIS IS THE METHOD I AM CALLING FOR MY BUTTON METHOD
-(NSArray*)fetchAllRecords {
NSManagedObjectContext *context = [self context]; //this context is conected to persistant container
NSError *error = nil;
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"UsefulCodes"];
NSArray *records = [context executeFetchRequest:request
error:&error];
if(error == nil && records.count > 0) {
return [records copy];
}
else {
//Handle error by returning new array
return [NSArray new];
}
}
The above code just sets the initial values I hard-coded into my arrays (I'm only interested in getting the values from presetList array to display in textfield) as well as accommodating any new codes and descriptions I've added to any arrays. Now here is the method in my "MainViewController" responsible for cycling through my array.
In header file I declare a property called num.
#property(nonatomic)int num;
This is the method in implementation file.
- (void)getQuickMorseCode {
NSArray *array = [[CoreDataManager sharedInstance] fetchAllRecords];
if(_num == 0 || _num > 0) {
if(_num >= array.count){
_num = 0;
}
//GETTING THE SPECIFIC INDEX OF THE ARRAY, THIS IS WHERE THE PROBLEM LIES
self.morseTextfield.text = array[_num];
[self convertInput:self.morseTextfield.text];
[self buttonAppear];
_num++;
}
}
My goal is to display the strings that are in the presetList array in my CoreDataManager file, but I'm unable to get that to pass into my textfield. Any insight to my problem is welcomed.
Your fetchAllRecords method returns an array of UsefulCodes objects. So each element of array is a UsefulCodes object. You cannot therefore assign the element to the text property of a textfield. That's the cause of your error.
You need instead to extract the relevant string from the UsefulCodes object. From your other code, you store the presetList values in the codename attribute of the UsefulCodes objects:
codeObj.codeName = [presetList objectAtIndex:i];
So, reverse that process to obtain the relevant string from the codename attribute:
UsefulCodes *codeObj = (UsefulCodes *)array[_num];
NSString *presetListValue = codeObj.codeName;
self.morseTextfield.text = presetListValue;
I have to assign countries, states & cities getting in response from JSON, in an NSMutableArray, Which is initialized in Modal Class.
I will have to remove all objects in order to set new states and cities, doing that crashes with error
incorrect checksum for freed object - object was probably modified
after being freed.
*** set a breakpoint in malloc_error_break to debug
then in answer https://stackoverflow.com/a/12050676/5568169 came to know that assigning nil to mutableArray will work, and it worked, But now User can again select another country, So now allocating memory [myMutableArray alloc] init]], gives me the same error i was getting in starting.
-(void)fetchStates:(NSString*)idString {
[registrationModalContactVC.allStateArray removeAllObjects];
registrationModalContactVC.allStateArray = nil;
[registrationModalContactVC.allStateDict removeAllObjects];
registrationModalContactVC.allStateDict = nil;
registrationModalContactVC.allStateArray = [NSMutableArray new];
registrationModalContactVC.allStateDict = [NSMutableDictionary new];
}
Kindly help
You should not be dong this :
[myMutableArray alloc] init]
What you mean to do is :
myMutableArray = [[NSMutableArray alloc] init];
i think your mutablearray is a datasource of a pickview , when you remove all objects, how is your pickview's status.
Removing below code is working, but it may give the same error again
registrationModalContactVC.allStateArray = nil;
registrationModalContactVC.allStateDict = nil;
registrationModalContactVC.allStateArray = [NSMutableArray new];
registrationModalContactVC.allStateDict = [NSMutableDictionary new];
Let me preface that my code has been obscured a little on purpose. I know the name won't be good. I am trying to add a widget to my app with the new iOS 8 functionality. I am using this link as a tutorial
Now, so far I have this in my ViewController when my submit button is called in my app. By this time I have all my data in that array to be passed on.
//Passes the array of times to the shared group to be called by the notification center widget.
NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.myGroup.TodayExtensionSharingDefaults"];
NSData *encodedArray = [NSKeyedArchiver archivedDataWithRootObject:tableViewController.TimeArray];
[sharedDefaults setObject:encodedArray forKey:#"TimesArray"];
[sharedDefaults synchronize];
However, my array stores a custom data model I created, so in my data model I have:
- (void)encodeWithCoder:(NSCoder *)encoder {
//Encode properties, other class variables, etc
[encoder encodeInt:_stopNumber forKey:#"stopNumber"];
[encoder encodeObject:_route forKey:#"route"];
[encoder encodeObject:_number forKey:#"number"];
[encoder encodeInt:_time forKey:#"time"];
[encoder encodeObject:_minutesOrApproaching forKey:#"#minutesOrApproaching"];
[encoder encodeObject:_noPrediction forKey:#"noPrediction"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super init];
if(self) {
//decode properties, other class vars
_stopNumber = [decoder decodeIntForKey:#"stopNumber"];
_route = [decoder decodeObjectForKey:#"route"];
_number = [decoder decodeObjectForKey:#"number"];
_time = [decoder decodeIntForKey:#"time"];
_minutesOrApproaching = [decoder decodeObjectForKey:#"minutesOrApproaching"];
_noPrediction = [decoder decodeObjectForKey:#"noPrediction"];
}
return self;
}
And then in my Widget I have this code being called:
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.myGroup.TodayExtensionSharingDefaults"];
NSData *myDecodedObject = [defaults objectForKey: #"TimesArray"];
NSArray *decodedArray =[NSKeyedUnarchiver unarchiveObjectWithData: myDecodedObject];
int i = 0;
for (ETA *eta in decodedArray) {
if(i == 0){
_stopNumber.text = eta.number;
}
UILabel *label = [timeSlots objectAtIndex:i];
label.text = eta.minutesOrApproaching;
i++;
}
My issue is that I keep getting:
* Terminating app due to uncaught exception 'NSInvalidUnarchiveOperationException', reason: '*
-[NSKeyedUnarchiver decodeObjectForKey:]: cannot decode object of class (ETA)'
enter code here
So I am a little off put because I don't know what I am doing wrong here. It would be really great if someone could help point me in the right direction. Thanks again!
So, turns out passing custom classes can be a pain. And although all the code seems to be right, I am still getting the error. So I stepped back and looked at my custom object and asked myself "What is it that I really need from this?" and using that process decided I only needed certain values, so with that I encrypted only those values and not the object. Since those values were ints and strings, they are built into iOS on how to encode and decode. From there, I was able to pass the values around thanks to #meda's answer and my idea.
- (void)viewDidLoad
{
binding.logXMLInOut = YES; // to get logging to the console.
StationDetailsJsonSvc_getAvailableStations *request = [[StationDetailsJsonSvc_getAvailableStations new] autorelease];
request.userName=#"twinkle";
request.password=#"twinkle";
StationDetailsJsonSoap11BindingResponse *resp = [binding getAvailableStationsUsingParameters:request];
for (id mine in resp.bodyParts)
{
if ([mine isKindOfClass:[StationDetailsJsonSvc_getAvailableStationsResponse class]])
{
resultsring = [mine return_];
NSLog(#"list string is%#",resultsring);
}
}
#pragma mark parsing
SBJsonParser *parserq = [[SBJsonParser alloc] init];
//if successful, i can have a look inside parsedJSON - its worked as an NSdictionary and NSArray
results= [parserq objectWithString:resultsring error:nil];
NSLog(#"print %#",results);
for (status in results)
{
NSLog(#"%# ",[status objectForKey:#"1" ]);
events=[status objectForKey:#"1"];
NSLog(#"get%#",events);
NSLog(#"events%#",events);
}
events=[status objectForKey:#"1"];
NSLog(#"post%#",events);
self.navigationController.navigationBarHidden=YES;
[whethertableview reloadData];
[super viewDidLoad];
}
this is my code am not getting tableview contents if i run my app crashes getting [NSCFString count]:unrecognized selector sent to instance
You should not get count on NSString but on arrays
you should call [yourString length] to check if the string has something.
You are trying to get the count of a string , which is crashing the App
There are various improvements you could make with this code, but I think I see the problem:
As you are not using ARC, you need to retain what you take out of the parser:
So instead of:
events=[status objectForKey:#"1"]
You need to do:
events= [[status objectForKey:#"1"] retain];
Your crash is caused by accessing a variable that has already been released. More than likely it is the events variable.
...and to add to this. events is probably an NSArray which 'count' is being called on. And [status objectForKey:#"1"] is returning a string... there are many possibilities which i'm speculating about. If events is an NSArray, this isn't the way to add objects to the array.. you repeatedly call events=[status objectForKey:#"1"]; in a loop too.
I have a global NSMutableArray and I need to update it with values. NSMutableArray is defined in the .h as follows;
#property (strong, nonatomic) NSMutableArray *myDetails;
In the viewDidLoad pre-populate like this;
NSDictionary *row1 = [[NSDictionary alloc] initWithObjectsAndKeys:#"1", #"rowNumber", #"125", #"yards", nil];
NSDictionary *row2 = [[NSDictionary alloc] initWithObjectsAndKeys:#"2", #"rowNumber", #"325", #"yards", nil];
NSDictionary *row3 = [[NSDictionary alloc] initWithObjectsAndKeys:#"3", #"rowNumber", #"525", #"yards", nil];
self.myDetails = [[NSMutableArray alloc] initWithObjects:row1, row2, row3, nil];
Then when the user changes a text field this code is run this;
-(void)textFieldDidEndEditing:(UITextField *)textField{
NSObject *rowData = [self.myDetails objectAtIndex:selectedRow];
NSString *yards = textField.text;
[rowData setValue:yards forKey:#"yards"];
[self.myDetails replaceObjectAtIndex:selectedRow withObject:rowData];
}
When stepping through the code on the line [rowData setValue:yards forKey:#"yards"]; it returns this error;
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'
The array is mutable, but what is in it... NSDictionary... is not. You grab an object out of the array...
NSObject *rowData = [self.myDetails objectAtIndex:selectedRow];
and then you try to mutate that object...
[rowData setValue:yards forKey:#"yards"];
The object in the array is the thing you are changing... and it is NSDictionary, immutable, and you can not change it. If you want the dictionary to be mutable, you have to use NSMutableDictionary