Changing value of a NSString - objective-c

I am having problems changing the value of an NSString.
It is declared in my class like this:
#property (strong, nonatomic)NSMutableString *votes;
When the object is created, it is set like this:
song.votes = [dict objectForKey:#"Votes"];
And finally is where the trouble occurs. Later in my code I try to modify the value like this:
song.votes =[responseArr valueForKey:#"CNT"];
This line is leading to this crash:
'NSInvalidArgumentException', reason: '-[__NSCFString setVotes]:
unrecognized selector sent to instance 0x14f84430'
I'm think my problems is caused by one of these:
1. Incorrectly setting the properties above. I've tried setting it as (copy, nonatomic) as well but it does the same thing.
2. i need to use an NSMutableString for this. I tried changing it to NSMutableString but it still crashes when it changes (admittedly I am initializing and changing it the way way when using NSMutableString, am not entirely sure how to change things when its Mutable.

I think the problem is in the way you're allocating / setting your song object. Somewhere between setting the first and the second value, you're probably deallocating song and then trying to set it's properties, or you're modifying it in such a way that it's not the same class type anymore.
unrecognized selector sent to instance 0x14f84430' pretty much sums it up for you. The second time you try to set the votes property, it tries to access the synthesized setter (setVotes) from song which is no longer the class you think it is.
From the error it looks like you may be re-allocating song as a NSString object. That's why it's trying to access a setVotes method on NSString and such a method does not exist, so it bails out and crashes.
Are you sure you're not doing something like song = [someString retain]; ?

Use -mutableCopy if you need a mutable copy of your NSString.
song.votes = [[dict objectForKey:#"Votes"] mutableCopy];
Assuming responseArr is an array, [responseArr valueForKey:#"CNT"] returns an array with the return value of each of the instances in responseArr. Your property is for a NSMutableString, but you set it to a NSArray.
(Also, do provide the actual error that you get when you crash instead of just saying 'it crashes'.)

Related

Xcode: #dynamic class variable not working

I have a class which declares a User and includes these variables:
(User.h file):
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSString * unid;
(User.m file):
#dynamic name;
#dynamic unid;
I have an array of values by parsing a string.
I then want to set the values accordingly:
(ViewController.m file):
[user setName:[returned objectAtIndex:1]];
[user setUnid:[returned objectAtIndex:2]];
When this is run the compiler gives me the following error:
unrecognized selector sent to instance
*** WebKit discarded an uncaught exception in the webView:shouldInsertText:replacingDOMRange:givenAction: delegate: <NSInvalidArgumentException> -[User setName:]: unrecognized selector sent to instance
When I comment out the setName line it works fine.
I then looked at the classes of the two objects from the returned array and they were both: __NSCFString
I then tried this piece of code:
(ViewController.m file):
[user setName:[returned objectAtIndex:2]];
Again the same error.
Why would the same input fail in one case and succeed in another if they are both expecting the same input?
Thanks.
EDIT:
This error is weird as this part of the app does not interact with any webviews. This returned array is parsed from a string gather from a webpage:
(ViewController.m file):
NSString *string = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://url_goes_here.com" encoding:NSUTF8StringEncoding error:&error];
NSArray *returned = [returned componentsSeparatedByString:#"#"];
However the unid is also parsed from this array without any problem.
The #dynmaic keyword means that you'll be providing the accessors yourself. If you want the compiler to create accessors for you, simply delete the #dynamic name declaration. (Because #synthesize is now the default, you don't have to use it explicitly.) Otherwise, you'll need to create the -name, -setName:, -unid, and -setUnid: methods yourself.
it is actually a set up class by xcode using the NSManagedObject subclass for core data
This is an important detail. In the case of managed objects, Core Data will provide the accessors for you and you just need the #dynamic property declaration to let the compiler know that it shouldn't generate accessors itself.
I'm a little confused as to why this error is coming from a web view delegate method. It might help if you could explain a little more about how your Core Data classes are interacting with a web view.
why would this work for the unid, but not the name
The error you're getting is an run time error -- an exception is being thrown. It's likely that the name accessor is simply the first one to be used; the same thing might happen for unid if that property were to be set first.
This error is weird as this part of the app does not interact with any webviews.
Another important clue. At this point, it sounds very much like you've got a bad pointer. You're sending -setName: to an object that's not what you think it is, and in this case it turns out to be a web view delegate. Try turning on NSZombies to help you track this down.

How to properly use makeObjectsPerformSelector: Getting error unrecognized selector

Let me start off by saying I am new to Objective C.
I am getting the error
atusMenuApp[24288:303] -[__NSCFConstantString createListItem]: unrecognized selector sent to instance 0x100002450
Here is my code:
selector = [NSMutableArray arrayWithObjects: #"nvda", #"aapl", #"goog", nil];
[selector makeObjectsPerformSelector:#selector(createListItem:) withObject:self];
- (void)createListItem:(NSString *)title {
//do some stuff
}
Now I have done plenty of looking around and it seems like the biggest reason for this issue is the addition of or lack of the :however I do believe I properly have that in place. Maybe I do not understand the use of makeObjectsPerformSelector very well as after look up the doc on it I found:
Sends to each object in the array the message identified by a given selector, starting with the first object and continuing through the array to the last object.
Any help would be great, Thanks!
[Only if you read the documentation (or thought a bit about why a method is named this way and not that), or even made the effort trying to understand the error message...]
The makeObjectsPerformSelector:withObject: method of NSArray does what it suggests it does: it makes the objects of the array perform the selector, that can have an optional argument. So
[selector makeObjectsPerformSelector:#selector(createListItem:) withObject:self];
will send the createListItem: message to every single NSString object in the selector array and pass in self as its argument. It won't perform the selector on self passing in the object. I. e., what you have is equivalent to
for (NSString *obj in selector) {
[obj createListItem:self];
}
Obviously, instead of this, you want the following:
for (NSString *obj in selector) {
[self createListItem:obj];
}
You don't even need that nasty method for this. A nice fast enumeration for loop will do it.
First you make an array of NSStrings. Then, you send them all the message createListItem. That's all fine and dandy, but NSString doesn't have any method called createListItem; just because you've defined an instance method called createListItem doesn't mean every instance of every class can use it. Only the class who's implementation file has the definition will be able to handle the message. For instance, I can't make a list of Car instances, then define the method fly in another class called Helicopter's implementation and expect to be able to call fly on an instance of Car; only Helicopter can use it. I recommend you read a good book on Objective-C and further familiarize yourself with classes, instances and instance methods.
You misunderstood the method.
It will call the method createListItem: with argument self over every object of the NSArray.
So the resulting call would be something like:
[#"nvda" createListItem:self];
...
Clearly that method doesn't exist for a NSString and there goes your exception.
If you need to apply a method of self to every object inside your array, simply loop through it.

Re-initialize NSMutableArray as NSMutableArray

I was having a problem with my app throwing an exception when calling removeObjectAtIndex on an NSMutableArray, saying that myLocationsArray was declared immutable. All other manipulation on that array was fine, it was most definitely declared correctly etc etc but somewhere in my app it was getting set as immutable. After investigating for a while trying to find where it was getting set immutable, I decided screw it and just redeclared the variable as such:
myLocationsArray = [[NSMutableArray alloc] initWithArray:[defaults
objectForKey:MYLOCATIONSARRAY_KEY]];
right before the removeObjectAtIndex call.
However I know this has got to be badwrong, I'm calling alloc/init twice on the same variable. However it's the only thing that has worked. Is there any way to remind this variable that it is an NSMutableArray without introducing memory leaks like I am?
NSUserDefaults returns immutable copy of your array. It doesn't matter whether you put NSArray or NSMutableArray in it, it always give you immutable copy back.
So, do this to get a mutable copy that you can work with
myLocationsArray = [[NSMutableArray alloc] initWithArray:[[[defaults objectForKey:MYLOCATIONSARRAY_KEY] mutableCopy] autorelease]];
or just this
myLocationsArray = [[defaults objectForKey:MYLOCATIONSARRAY_KEY] mutableCopy];
I would suggest to set a breakpoint on the line where your program is throwing an exception (the one containing removeObjectAtIndex) and inspect with the debugger the real type of the array. If you go with you mouse over the array name, a popup menu will display giving you all the information you need about the pointed object.
What I expect is that you find out this way that the object is an NSArray (vs. NSMutableArray) and then trace back to the point where you initialized it in the first place.
It looks like you're working with NSUserDefaults. All objects you get out of NSUserDefaults are always immutable, regardless of what you stored into it. NSUserDefaults doesn't keep a reference to the specific object you set into it, it keeps the data. It's effectively making a copy. When you get something out of NSUserDefaults, it makes a new (immutable) object from the data it has stored and gives that to you.
Unsurprisingly, you can't change what's stored in NSUserDefaults by mutating what you (think you) stored in it. You can only change what's stored by replacing what you previously stored by storing something anew.
The declaration should not matter; your error is a run-time error. It sounds like your myLocationsArray variable has been assigned an immutable array (NSArray) though whether it is being re-assigned somewhere or was always immutable is impossible to say from your code fragment.

Problem assigning value obtained from [array objectAtIndex:]

In my Piano class, I have a property (Keys is another custom class)
#property (nonatomic, retain) Keys *lastPlayed;
In one of my Piano methods, I set the value of lastPlayed using an object from an array of Key objects.
self.lastPlayed = [allKeys objectAtIndex:variable];
The above line of code causes the program to crash.
I've noticed that if I hardcode a specific Key object from the allKeys array, then it works fine. Like so:
self.lastPlayed = keyC;
Interestingly, it doesn't crash if I put the crashing code into a different method.
How can I prevent the crash?
EDIT:
I call this method in the Keys class, where my piano is the delegate
[delegate deliverTagwithNameTag:self.tag]
the piano then responds
- (void) deliverTagwithNameTag:(int)nameTag {
self.lastPlayed = [allKeys objectAtIndex:nameTag];
}
You're probably not getting a plain unexplained crash, you're probably raising an exception. You can watch the console to find out which exception you raised. Normally in this sort of situation it'll be something useful to tell you either that you're asking the array for an out-of-bounds value (which could happen if variable were collecting an incorrect value somehow), that the array itself is invalid (which could be a memory allocation problem) or that the thing returned can't be stored as lastPlayed (which would normally indicate you're doing something custom in the setter and getting an unexpected type of class).
So to prevent the crash, check your console and look for one of those problems.

NSString unexpectedly becomes __NSCFDictionary

I have this very strange problem, I'm new to objective-c and it probably comes from depths which I don't comprehend yet.
So, in my header file I declare the variable
NSString *curTitle;
then in .m file I synthesize it:
curTitle = [[NSString alloc] init];
after that in other method I assign it:
curTitle = string; // string is an instance of NSString
and at the end of the day when I'm trying to assign
slide.title = curTitle; //slide is a managed object (CoreData)
I'm getting this error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Unacceptable type of value for attribute: property = "title"; desired type = NSString; given type = __NSCFDictionary; value = {
}.'
Interesting fact that in iphone SDK 3.2 it worked, but after I installed SDK 4 I have this error
Another interesting fact that if make my curTitle property of my class (with #property and #synthesize) it also works
Any ideas?
Thanks
When an object seems to change class, it's almost always because it has been deallocated, and another object is now residing on the same memory location. All object variables are actually pointers to memory locations (that's what the * means), and unlike in many other languages you have to always remember that you're working with memory locations. (Well, not always, once you get the hang of it. But definitely when you're debugging.)
To debug these problems, it can be very useful to use NSZombie. Just search SO or the web for info.
then in .m file I synthesize it:
curTitle = [[NSString alloc] init];
This is not synthesizing. What you are doing here is merely assigning a value to the variable. More precisely, you create an object somewhere in memory (alloc) and initialize it (init) and then you set the value of curTitle to point to that memory location.
There is no need for you to have this line in your code at all.
curTitle = string;
Here you are overwriting the old value of curTitle with a pointer to another string. Your problem is most likely that that other string later gets deallocated, and the memory location gets reused to hold another object (a dictionary in this case). (If you don't know about the retain/release mechanisms, you need to read up on those to understand what happens.)
slide.title = curTitle;
Since curTitle is pointing to a memory location that has been re-used to hold a random object (or even worse: garbage) this line will fail. In fact, you're lucky that it fails, because if it didn't (if the location hadn't been reused yet) it would be even harder to detect the bug.
What you should do is to declare a property, then synthesize it and access the variable through the property:
self.curTitle = aString;
This will make sure that you actually copy and take ownership of the string so that even if the original string is released, you will still have a valid copy.