No visible #interface for primitive accessor - ios

I'm trying to implement a getter method for a simple transient property. The transient property is a fullName property. Typical example of fullName = firstName + lastName.
I'm developing an iOS app (just in case something related works differently on OS X)
Following the 'Mastering Core Data' WWDC 2010 Keynote I've created a category for my Person NSManagedObject subclass. In that category I've added the following method:
- (NSString *)fullName {
[self willAccessValueForKey:#"fullName"];
NSString *fullName = [self primitiveFullName];
[self didACCessValueForKey:#"fullName"];
if (fullName == nil) {
fullName = [NSString stringWithFormat:#"%# %#", self.firstName, self.lastName];
[self setPrimitiveFullName:fullName];
}
return fullName;}
Person class has been created automatically by Xcode and has the fullName property and its implementation with #dynamic.
When I try to compile the project I get an error for this category saying "No visible #interface for 'Person' declares selector 'primitiveFullName'".
Why I'm getting this error when Apple documentation says "For example, given an entity with an attribute firstName, Core Data automatically generates firstName, setFirstName:, primitiveFirstName, and setPrimitiveFirstName:." ??
The error is a compile error, not a warning
Should I something special to have the primitive accessors generated?

primitiveFullName and setPrimitiveFullName definitely will be generated automatically in runtime. But in compile time, compiler cannot find these methods. To suppress compile error when you invoke these methods, you should declare the prototype of these methods.
If when in 2010, Objective-C compiler said only warnings to invoke those undeclared methods. But after ARC introduced, Objective-C compiler disallow invoking such undeclared methods.
Like below:
#interface Person (PrimitiveAccessors)
- (NSString *)primitiveFullName;
- (void)setPrimitiveFullName:(NSString *)newName;
#end
#implementation Person (TransientProperties)
- (NSString *)fullName {
[self willAccessValueForKey:#"fullName"];
NSString *fullName = [self primitiveFullName];
[self didAccessValueForKey:#"fullName"];
if (fullName == nil) {
fullName = [NSString stringWithFormat:#"%# %#", self.firstName, self.lastName];
[self setPrimitiveFullName:fullName];
}
return fullName;
}
#end

First one comment on your design not an answer to the Q itself, but strongly related:
Your implementation is inconvenient: If you have a computed property, you should compute it. You should not store it. What happens, if firstName or lastName changed? Do you want to overwrite the setters for this properties, too, to nil fullName? If it is a computed property, compute it.
- (NSString*)fullName
{
return [NSString stringWithFormat:#"%# %#", [self valueForKey:#"firstName"], [self valueForKey:#"lastName"]];
}
Done.
This should solve your problem, because it is a different design. However, if you want to keep your old approach, you can use -primitiveValueForKey: and -setPrimitiveValue:forKey:.

Related

Objective-C method signatures: Parameter types can differ between declaration and implementation?

I can declare a method in the #interface having parameter type NSString*:
- (id) initWithString:(NSString*)str;
while in the implementation it is NSNumber*:
- (id) initWithString:(NSNumber*)str
For a full example, see the code below. When calling [Work test] the output is a.x = Hi, so the passed-in NSString* went through and one can see that the "correct" initWithString method was called.
Why is this code accepted by the compiler?
Can I make the compiler complain when parameter types differ?
Citing from Apple's documentation Defining Classes :
The only requirement is that the signature matches, which means you must keep the name of the method as well as the parameter and return types exactly the same.
My test code:
#interface ClassA : NSObject
#property (strong, nonatomic) NSNumber *x;
- (id) initWithString:(NSString*)str;
- (void) feed:(NSString*)str;
#end
#implementation ClassA
- (id) initWithString:(NSNumber*)str
{
self = [super init];
if (self) {
self.x = str;
}
return self;
}
- (void) feed:(NSNumber*)str
{
self.x = str;
}
#end
#implementation Work
+ (void) test
{
ClassA *a = [[ClassA alloc] initWithString:#"Hi"];
NSLog(#"a.x = %#", a.x);
}
#end
I added the feed method to see, whether it is "special" to init-like methods, but the compiler doesn't complain either.
(Ran this on Yosemite / Xcode 6.4 / iOS8.4 Simulator.)
PS: If I didn't use the right terms, please correct me :-)
Can I make the compiler complain when parameter types differ?
There's a warning for this which you can activate by including the following line in the header:
#pragma clang diagnostic error "-Wmethod-signatures"
You can also put -Wmethod-signatures into the project's "Other Warning Flags" Xcode build setting to activate this for the whole project.
I don't really understand why Apple is so hesitant to activate helpful warnings like this by default.
My standard pattern on virtually every project is to put -Weverything in "Other Warning Flags". This activates all warnings clang has to offer.
Since there are some warnings that are a little too pedantic or don't serve my coding style, I individually deactivate unwanted warning types as they pop up.
I'm surprised by the quote you found stating that param and return types matter to the uniqueness of the method signature. Re-reading, I think you found a bug in the doc.
Defining a parameter type in the interface will generate a warning for callers that do not pass that type (or cast the parameter to that type), no matter the implementation. Changing the parameter type in the implementation is exactly like casting the parameter within the method. Nothing wrong with that, not even a cause for warning. So long as the different type shares methods (polymorphic or inherited) with the declared type.
In other words, restating by example...
The following will cause a compiler error, proving that distinct param types offers no distinction to the compiler (same is true for return type)...
// .h
- (void)foo:(NSString *)str;
// .m
- (void)foo:(NSString *)str {
NSLog(#"called foo %#", [str class]);
}
- (void)foo:(NSNumber *)str { <----- duplicate declaration error
}
The following will cause no compiler warnings, errors or runtime errors...
// .h
- (void)foo:(NSString *)str;
// .m
- (void)foo:(NSNumber *)str {
// everything implements 'class', so no problem here
NSLog(#"called foo %#", [str class]);
}
The following is exactly like the previous example in every respect...
// .h
- (void)foo:(NSString *)str;
// .m
- (void)foo:(NSString *)str {
NSNumber *number = (NSNumber *)str;
NSLog(#"called foo %#", [number class]);
}
The following will cause no warnings, but will generate a runtime error because we are abusing the cast by invoking a method that the passed type doesn't implement (presuming the caller calls with a string as the interface indicates)...
// .h
- (void)foo:(NSString *)str;
// .m
- (void)foo:(NSNumber *)str {
NSLog(#"does str equal 2? %d", [str isEqualToNumber:#2]); <--- crash!
}
All of the foregoing matches intuition and behavior in practice, just not that passage in the doc. Interesting find!
In Objective-C a method is defined as a string (known as a selector) in the form of doSomethingWithParam:anotherParam:. Or in your case it will be initWithString:. Note there's no parameter types in these strings. One side-effect of defining methods like this is that Objective-C, unlike Java or C++ doesn't allow overloading operators by just changing the parameter type. Another side-effect is the behavior you observed.
EDIT: Additionally, it appears that the compiler does not look at the implementation at all when checking method calls, just the interface. Proof: declare a method in a header, don't specify any implementation for that method, and call this method from your code. This will compile just fine, but of course you'll get an "unrecognized selector" exception when you run this code.
It'd be great if someone could provide a nice explanation of the default compiler behavior.

Objective-C get subclass

Let's say I have a UIViewController Subclass,
let's call it MyAppBaseViewController:
and
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSString *subclassName = ...;
NSLog(#"%# did appear", subclassName);
}
How would I be able to get the subclass name, not the name of the current class, from within the parent, without adding any properties to the implementation or anything like that?
You are confused.
An object is an instance of some subclass. It can, and often does, inherit from a long chain of parent classes.
The object is still a particular class.
If you use
NSString *myClassName = [NSString stringWithFormat: #"%s", class_getName([self class)];
It will give you the name of the current object's class. Not the parent class. The current object.
Edit:
As the other poster pointed out, the function NSStringFromClass is much easier. Use that instead:
NSString *myClassName = NSStringFromClass([self class]);

NSDictionary<FBGraphUser> *user syntax explanation

In the Facebook iOS SDK requests are returned with the following handler:
^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error) { }
The user variable can then be accessed with calls like these...
self.userNameLabel.text = user.name;
self.userProfileImage.profileID = user.id;
This syntax is somewhat similar to the syntax id <protocolDelegate> object syntax that is a common property declaration, except for that the NSDictionary is the id object explicitely, and that dictionary conforms to the protocol? But where does the dot syntax come from and how does one state that an arbitrary NSFoundation object corresponds to a protocol without subclassing the object itself and making it conform?
I did some additional research about dot notation and NSDictionary and it appears that it is not possible to use dot notation on a dictionary without adding a category to NSDictionary. However, I did not see any reference of the <> syntax in the Apple Documentation to indicate that this particular instance of NSDictionary conformed to that notation.
And the Facebook documentation is a little sparse on how this wrapping works:
The FBGraphUser protocol represents the most commonly used properties
of a Facebook user object. It may be used to access an NSDictionary
object that has been wrapped with an FBGraphObject facade.
If one follows this lead to the FBGraphObject documentation then there is methods that return dictionaries that conform to this "facade..." but no further explanation on how one goes about wrapping a dictionary.
So I guess my questions are a few:
What would the underlying code look like to make this sort of
syntax work?
Why does it exist?
Why would facebook implement it this way as opposed to just
making an object that they can convert the data into?
Any explanation or insight would be very appreciated!
Basically, NSDictionary<FBGraphUser> *user, implies an object that inherits from NSDictionary, adding functionality (specifically, typed access) declared by the FBGraphUser protocol.
The reasons behind this approach are described in quite a bit of detail in the FBGraphObject documentation (the FBGraphUser protocol extends the FBGraphObject protocol). What might be confusing you is that FBGraphObject is a protocol (described here) and a class (described here), which inherits from NSMutableDictionary.
In terms of inner implementation, it's some pretty advanced Objective-C dynamic magic, which you probably don't want to worry about. All you need to know is you can treat the object as a dictionary if you wish, or use the additional methods in the protocol. If you really want to know the details, you can look at the source code for FBGraphObject, in particular, these methods:
#pragma mark -
#pragma mark NSObject overrides
// make the respondsToSelector method do the right thing for the selectors we handle
- (BOOL)respondsToSelector:(SEL)sel
{
return [super respondsToSelector:sel] ||
([FBGraphObject inferredImplTypeForSelector:sel] != SelectorInferredImplTypeNone);
}
- (BOOL)conformsToProtocol:(Protocol *)protocol {
return [super conformsToProtocol:protocol] ||
([FBGraphObject isProtocolImplementationInferable:protocol
checkFBGraphObjectAdoption:YES]);
}
// returns the signature for the method that we will actually invoke
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
SEL alternateSelector = sel;
// if we should forward, to where?
switch ([FBGraphObject inferredImplTypeForSelector:sel]) {
case SelectorInferredImplTypeGet:
alternateSelector = #selector(objectForKey:);
break;
case SelectorInferredImplTypeSet:
alternateSelector = #selector(setObject:forKey:);
break;
case SelectorInferredImplTypeNone:
default:
break;
}
return [super methodSignatureForSelector:alternateSelector];
}
// forwards otherwise missing selectors that match the FBGraphObject convention
- (void)forwardInvocation:(NSInvocation *)invocation {
// if we should forward, to where?
switch ([FBGraphObject inferredImplTypeForSelector:[invocation selector]]) {
case SelectorInferredImplTypeGet: {
// property getter impl uses the selector name as an argument...
NSString *propertyName = NSStringFromSelector([invocation selector]);
[invocation setArgument:&propertyName atIndex:2];
//... to the replacement method objectForKey:
invocation.selector = #selector(objectForKey:);
[invocation invokeWithTarget:self];
break;
}
case SelectorInferredImplTypeSet: {
// property setter impl uses the selector name as an argument...
NSMutableString *propertyName = [NSMutableString stringWithString:NSStringFromSelector([invocation selector])];
// remove 'set' and trailing ':', and lowercase the new first character
[propertyName deleteCharactersInRange:NSMakeRange(0, 3)]; // "set"
[propertyName deleteCharactersInRange:NSMakeRange(propertyName.length - 1, 1)]; // ":"
NSString *firstChar = [[propertyName substringWithRange:NSMakeRange(0,1)] lowercaseString];
[propertyName replaceCharactersInRange:NSMakeRange(0, 1) withString:firstChar];
// the object argument is already in the right place (2), but we need to set the key argument
[invocation setArgument:&propertyName atIndex:3];
// and replace the missing method with setObject:forKey:
invocation.selector = #selector(setObject:forKey:);
[invocation invokeWithTarget:self];
break;
}
case SelectorInferredImplTypeNone:
default:
[super forwardInvocation:invocation];
return;
}
}
This syntax is somewhat similar to the syntax id object syntax
"Somewhat similar"? How'bout "identical"?
and that dictionary conforms to the protocol
Nah, the declaration says that you have to pass in an object of which the class is NSDictionary, which, at the same time, conforms to the FBGraphUser protocol.
But where does the dot syntax come from
I don't understand this. It comes from the programmer who wrote the piece of code in question. And it is possible because the FBGraphUser protocol declares some properties, which can then be accessed via dot notation.
and how does one state that an arbitrary NSFoundation object corresponds to a protocol without subclassing the object itself and making it conform?
It's not called "NSFoundation", just Foundation. And it's not the object that doesn't "correspond" (because it rather "conforms") to the protocol, but its class. And you just showed the syntax for that yourself.
And how is it implemented? Simple: a category.
#import <Foundation/Foundation.h>
#protocol Foo
#property (readonly, assign) int answer;
#end
#interface NSDictionary (MyCategory) <Foo>
#end
#implementation NSDictionary (MyCategory)
- (int)answer
{
return 42;
}
#end
int main()
{
NSDictionary *d = [NSDictionary dictionary];
NSLog(#"%d", d.answer);
return 0;
}
This is an SSCCE, i. e. it compiles and runs as-is, try it!
What would the underlying code look like to make this sort of syntax work?
Answered above.
Why does it exist?
Because the language is defined like so.
Why would facebook implement it this way as opposed to just making an object that they can convert the data into?
I don't know, ask the Facebook guys.

With CoreData, if I have an #dynamic property, can I override its getter just like it was #synthesized? (Lazy Instantiation)

Using CoreData I created an entity, then I subclassed it into its own file, where it has the #propertys, then it has the #dynamic parts in the .m file.
When I want something to have a certain value if it's never been set, I always use lazy instantiation, like follows:
- (NSString *)preview {
if ([self.body length] < 200) {
_preview = self.body;
}
else {
_preview = [self.body substringWithRange:NSMakeRange(0, 200)];
}
return _preview;
}
But how do I do this with #dynamic properties? If I do the same thing, it says _preview is an undeclared property, but it's in the .h file. What do I do different to lazy instantiate it?
One standard method is to define preview as a transient attribute in the Core Data model (so that the value is not actually stored in the database), and implement a custom getter method. In your case it would look like:
- (NSString *)preview
{
[self willAccessValueForKey:#"preview"];
NSString *preview = [self primitiveValueForKey:#"preview"];
[self didAccessValueForKey:#"preview"];
if (preview == nil) {
if ([self.body length] < 200) {
preview = self.body;
} else {
preview = [self.body substringWithRange:NSMakeRange(0, 200)];
}
[self setPrimitiveValue:preview forKey:#"preview"];
}
return preview;
}
(You can provide custom getter, setter methods for #dynamic properties. However, Core Data
properties are not simply backed up by instance variables. That is the reason why you cannot
access _preview.)
If you need the preview to be re-calculated if the body attribute changes, then you
must also implement a custom setter method for body that sets preview back to nil.
For more information, read Non-Standard Persistent Attributes in the "Core Data Programming Guide".
Update: The current version of the Core Data Programming Guide does
not contain that chapter anymore. You can find an archived version
from the Way Back Machine. Of course this has to be taken with
a grain of salt since it is not part of the official documentation
anymore.
See documentation on using primitiveValueForKey:
basically:
#dynamic name;
- (NSString *)name
{
[self willAccessValueForKey:#"name"];
NSString *myName = [self primitiveName];
[self didAccessValueForKey:#"name"];
return myName;
}
- (void)setName:(NSString *)newName
{
[self willChangeValueForKey:#"name"];
[self setPrimitiveName:newName];
[self didChangeValueForKey:#"name"];
}

NSDictionary: method only defined for abstract class. My app crashed

My app crashed after I called addImageToQueue. I added initWithObjects: forKeys: count: but it doesn't helped me.
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '*** -[NSDictionary initWithObjects:forKeys:count:]:
method only defined for abstract class.
Define -[DictionaryWithTag initWithObjects:forKeys:count:]!'
my code
- (void)addImageToQueue:(NSDictionary *)dict
{
DictionaryWithTag *dictTag = [DictionaryWithTag dictionaryWithDictionary:dict];
}
#interface DictionaryWithTag : NSDictionary
#property (nonatomic, assign) int tag;
- (id)initWithObjects:(id *)objects forKeys:(id *)keys count:(NSUInteger)count;
#end
#implementation DictionaryWithTag
#synthesize tag;
- (id)initWithObjects:(id *)objects forKeys:(id *)keys count:(NSUInteger)count
{
return [super initWithObjects:objects forKeys:keys count:count];
}
#end
Are you subclassing NSDictionary? That's not a common thing to do in Cocoa-land, which might explain why you're not seeing the results you expect.
NSDictionary is a class cluster. That means that you never actually work with an instance of NSDictionary, but rather with one of its private subclasses. See Apple's description of a class cluster here. From that doc:
You create and interact with instances of the cluster just as you would any other class. Behind the scenes, though, when you create an instance of the public class, the class returns an object of the appropriate subclass based on the creation method that you invoke. (You don’t, and can’t, choose the actual class of the instance.)
What your error message is telling you is that if you want to subclass NSDictionary, you have to implement your own backend storage for it (for example by writing a hash table in C). It's not just asking you to declare that method, it's asking you to write it from scratch, handling the storage yourself. That's because subclassing a class cluster directly like that is the same as saying you want to provide a new implementation for how dictionaries work. As I'm sure you can tell, that's a significant task.
Assuming you definitely want to subclass NSDictionary, your best bet is to write your subclass to contain a normal NSMutableDictionary as a property, and use that to handle your storage. This tutorial shows you one way to do that. That's not actually that hard, you just need to pass the required methods through to your dictionary property.
You could also try using associative references, which "simulate the addition of object instance variables to an existing class". That way you could associate an NSNumber with your existing dictionary to represent the tag, and no subclassing is needed.
Of course, you could also just have tag as a key in the dictionary, and store the value inside it like any other dictionary key.
From https://stackoverflow.com/a/1191351/467588, this is what I did to make a subclass of NSDictionary works. I just declare an NSDictionary as an instance variable of my class and add some more required methods. It's called "Composite Object" - thanks #mahboudz.
#interface MyCustomNSDictionary : NSDictionary {
NSDictionary *_dict;
}
#end
#implementation MyCustomNSDictionary
- (id)initWithObjects:(const id [])objects forKeys:(const id [])keys count:(NSUInteger)cnt {
_dict = [NSDictionary dictionaryWithObjects:objects forKeys:keys count:cnt];
return self;
}
- (NSUInteger)count {
return [_dict count];
}
- (id)objectForKey:(id)aKey {
return [_dict objectForKey:aKey];
}
- (NSEnumerator *)keyEnumerator {
return [_dict keyEnumerator];
}
#end
I just did a little trick.
I'm not sure that its the best solution (or even it is good to do it).
#interface MyDictionary : NSDictionary
#end
#implementation MyDictionary
+ (id) allocMyDictionary
{
return [[self alloc] init];
}
- (id) init
{
self = (MyDictionary *)[[NSDictionary alloc] init];
return self;
}
#end
This worked fine for me.

Resources