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.
Related
My apologies if this has already been asked and answered. I am new to Objective-C and I am trying to create a project that contains an object with NSMutableString and I am creating an NSMutableArray of those objects.
Each of the strings in the object are declared as follows:
#property (assign) NSMutableString* propname;
In the initialization routine (initStringObject) for the object I am setting each of the strings as follows:
self.propname = [NSMutableString stringWithCapacity:16];
[self.propname setString:#"Name"];
There are a number of properties with multiple NSMutableStrings, a couple of NSInteger and a float. All NSMutableStrings are allocated with different capacities.
For the NSMutableArray, I am declaring that in the interface section of the view controller .m file as follows:
#property (strong) NSMutableArray *objectarray;
In the loadview, routine I am initializing the array as follows:
self.objectarray = [NSMutableArray array];
[self.objectarray addObject:[[StringObject alloc] initStringObject];
The project builds fine but when I go to populate the view with the information in the object, the strings are corrupted. The integer and float values in the object are correct. I figure I must be losing the pointer to the correct location in memory but I cannot figure out what is going on. Eventually, if I keep running the program, I get an EXC_BAD_ACCESS error message.
This is an OS X application.
Can anyone see what I am doing wrong?
Thank you in advance.
I suspect it's the assign attribute in #property (assign). Use strong (the default) instead to have ARC properly manage the string objects.
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'.)
I am using Key-Value Coding to simplify updating instances of a model class:
#interface NewsItem : NSObject
{
}
#property (nonatomic, copy) NSString *title;
#property (nonatomic, copy) NSString *description;
#property (nonatomic, copy) NSString *link;
#property (nonatomic, copy) NSString *date;
using:
SEL selectorName = NSSelectorFromString(elementName);
if ([self.newsItem respondsToSelector:selectorName])
{
NSString *sanitisedElement = [self sanitiseElement:self.currentElementData];
[self.newsItem setValue:sanitisedElement forKey:elementName];
}
This works well but the 'description' property doesn't 'smell' right to me as it has overridden the base NSObject description getter (+ (NSString *)description). If the description getter is invoked now it will return irrelevant information when the caller would be expecting a description of the class.
Is it possible to safely proceed with Key-Value Coding for this class (given that I am bound to these property names by the external data source)? Or would it be wise to change the property names and manually check keys/set values instead?
You could override description in your class. This method is usually used only for debugging
and no caller can expect a specific output of that method.
But I see more general problems in your code. It is only checked that a method with the
given name exists. This does not imply that this method corresponds to a property, and even then, it does not imply that there is a setter for that property.
For example, every NSObject responds to the selector "init", so if the external
data source sends that key as "elementName", your code would immediately crash.
Therefore, an explicit list of "known keys" is needed. But then you can as well
use a mapping (NSDictionary) from external element names to internal properties
to avoid any conflicts.
I think that you are confusing methods with properties, and you are making things more complicated that how they are.
Is enough that, given an elementName that contains directly the setter name (i.e.: setDate), you invoke the selector passing that argument the object argument:
SEL selectorName = NSSelectorFromString(elementName); // elementName something like "setDate"
if ([self.newsItem respondsToSelector:selectorName])
{
[self.newsItem performSelector: selectorName withObject: sanitisedElement];
}
As for the description method, it has overridden NSObject's description, so you have two choices: name it in another way, or leave it like it is, and invoke it on super when you need the object description, with the help of Objective-C runtime:
struct objc_super superclass= { self.newItem, [self.newItem superclass] };
NSString* desc= objc_msgSendSuper(&superclass, #selector(description));
You can always override inherited methods.
By creating a property whose getter is the same as the signature of An inherited method, you are overriding it.
Is it bad? Yes if your implementation is not useful for debugging.
As best practice for KVC and KVO purposes it is a good idea to avoid potentially clashing with common inherited methods properties and ivars.
The common approach to this is to make longer property and method names and to make them more likely to be unique. One common way is by prefixing all yours with an abbreviation common to your class or framework or code.
Using something commonly used by Apple is likely to bite you in a rare and hard to debug way.
It's especially a bad idea to do this when core data is involved.
Don't be reluctant to make things longer. Code completion will type for you. Plus, a nice side effect of class specific prefixing is pseudo not only the pseudo namespace but that your class specific properties, variables, constants and methods will bubble up first in code completion.
I'm currently using the iOS 5 SDK trying to develop my app.
I'm trying to make an NSString a property, and then to synthesize it in the .m file (I have done this before with no issues). Now, I came across this: "Semantic Issue: Property's synthesized getter follows Cocoa naming convention for returning 'owned' objects."
This is my code:
.h
#interface ViewController : UIViewController {
NSString *newTitle;
}
#property (strong, nonatomic) NSString *newTitle;
.m
#synthesize newTitle;
Does anyone have a clue how I could fix this?
Thanks!!
My guess is that the compiler version you’re using follows the memory management rules for declared properties, too — more specifically, for declared properties’ accessors:
You take ownership of an object if you create it using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”.
A property named newTitle, when synthesised, yields a method called -newTitle, hence the warning/error. -newTitle is supposed to be a getter method for the newTitle property, however naming conventions state that a method whose name begins with new returns an object that’s owned by the caller, which is not the case of getter methods.
You can solve this by:
Renaming that property:
#property (strong, nonatomic) NSString *theNewTitle;
Keeping the property name and specifying a getter name that doesn’t begin with one of the special method name prefixes:
#property (strong, nonatomic, getter=theNewTitle) NSString *newTitle;
Keeping both the property name and the getter name, and telling the compiler that, even though the getter name starts with new, it belongs to the none method family as opposed to the new method family:
#ifndef __has_attribute
#define __has_attribute(x) 0 // Compatibility with non-clang compilers
#endif
#if __has_attribute(objc_method_family)
#define BV_OBJC_METHOD_FAMILY_NONE __attribute__((objc_method_family(none)))
#else
#define BV_OBJC_METHOD_FAMILY_NONE
#endif
#interface ViewController : UIViewController
#property (strong, nonatomic) NSString *newTitle;
- (NSString *)newTitle BV_OBJC_METHOD_FAMILY_NONE;
#end
Note that even though this solution allows you to keep newTitle as both the property name and the getter name, having a method called -newTitle that doesn’t return an object owned by the caller can be confusing for other people reading your code.
For the record, Apple have published Transitioning to ARC Release Notes, in which they state:
You cannot give a property a name that begins with new or copy.
They’ve already been notified that their statement is not quite accurate: the culprit is the getter method name, not the property name.
Edit 17 Jan 2015: I’ve just noticed a recent commit to Clang that suggests option 3 above (using objc_method_family(none)), including a fix-it, for the general case where a property name matches one of the special method family prefixes. Xcode will likely incorporate this change eventually.
Unacceptable Object Names
newButton
copyLabel
allocTitle
Acceptable Object Names
neueButton
mCopyLabel
_allocTitle
#arc #auto-synthesized #xcode-4.6.1
** EDIT **
Apparently you can't use mutableCopy either.
The name of the member starting with new is what triggers the warning. Change the name to editedTitle and the warning will go away. I was unable to find documentation confirming this but through testing was able to determine that member variables that begin with 'new' aggravate the compiler.
ARC does not allow to use "New...." in property name. but you can use "newTitle" by changing getter name.
#property (nonatomic, strong, getter=theNewTitle) NSString *newTitle;
It doesn't look like what Bavarious was suggesting was what you wanted to do. All you want to do is declare an instance variable NewTitle and then synthesize the property. We used to have to declare the instance variable and property. No more.
Now, I believe the right way of doing this is the following:
.h
#interface ViewController : UIViewController
#property (nonatomic, strong) NSString *newTitle;
.m
#synthesize newTitle = _newTitle; // Use instance variable _newTitle for storage
The instance variable for the property newTitle is synthesized. You don't want your instance variable to be the same as your property - too easy to make mistakes.
See Example: Declaring Properties and Synthesizing Accessors
In CoreData if you use "new..." in attribute (compile normally) it will crash randomly with a "bad access" exception.
There is no crash log and the line shown with the "All Exceptions Breakpoint" will not help you at all.
Writing a setter manually with the name same as the property's removed this warning.
NS_RETURNS_NOT_RETAINED is used to solve the naming problem.
#property (nonatomic, copy) NSString *newTitle NS_RETURNS_NOT_RETAINED;
We can find its definition as follows:
#define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
The 'ns_returns_not_retained' attribute is the complement of 'ns_returns_retained'. Where a function or method may appear to obey the Cocoa conventions and return a retained Cocoa object, this attribute can be used to indicate that the object reference returned should not be considered as an "owning" reference being returned to the caller. The Foundation framework defines a macro NS_RETURNS_NOT_RETAINED that is functionally equivalent to the one shown below.
Besides the issue that you should/can't use "new" in front of you property names, let say one more thing: Try to avoid "new" in front of names in general. "New" is dependent on time. Currently it is new for you, but some time later you maybe want to implement something new again. So using "new" in names is always bad. Try to think this way: In the programming world, "new" is always creating something: a new instance of something.
In your case when you want to assign a different title then the current name your property titleReplacement.
One more thing: Try to name functions and methods with the verb first, like setSomething or getSomething.
But in properties try to name the object first, like heightMinimum, heightMaximum, etc. -> when you use your inspector when you are coding, you always looking for objects. Try it out. ;-)
try this:-
#property (nonatomic,retain) NSString *newTitle;
I am doing a value object / Entity, that holds data for my model.
I get the data from a web service as JSON, now, instead of moving all the different objects from the parsed JSON over into different properties on my Entity. i.e. reading out the NSString for the #"name" key and setting it to [Entity setName:[JSONDictionary objectForKey:#"name"] etc. My Entity has one actual property,
NSDictionary *dataDictionary, this property hold the JSON dictionary as it left the parser.
Now when I need the name value I write an accessor that looks like this:
- (NSString*) name {
return [self.dataDictionary objectForKey:#"name"];
}
This is nice, I don't have to do any work unless there is a request for that particular property.
Now my question is how do I best tell the compiler that the accessor exists, but does not hold a "real" property.
I have this in my interface:
#property(nonatomic, retain) NSString *name;
And the #synthesize in my implementation, but this seems to create an overhead in my logic. Objective C will, as far as I understand, make a room in memory for me to store an object of type NSString when I do the #property(nonatomic, retain) and technically I don't need this as I am already storing this value in the the NSDictionary *dataDictionary
If I make it #dynamic I guess I would also have to provide a setter, which I would never need.
So, Is there a syntax that lets me create the illusion to all objects accessing the Entity that these are "normal" properties, but internally in the Entity not alloc/store unnecessary objects or write more code than is needed?
Declare a name method in your interface, not a property.
- (void)name;