NSManagedObject with Category and Delegate - objective-c

I created a NSManagedObject called MapState. I then created a category for it to call some methods and store some extra variables.
.h
#import "MapStateDB.h"
#protocol MapStateDelegate;
#interface MapStateDB (MapState)
#property (weak, nonatomic) id <MapStateDelegate> delegate;
-(void)selectedSceneObject:(SceneObject *)sceneObject;
-(void)removeDisplayedScene;
#end
#protocol MapStateDelegate <NSObject>
-(void)displayScene:(SceneDB *)scene inState:(NSString *)state;
-(void)removeScene:(SceneDB *)scene;
#end
In the .m:
#dynamic delegate;
-(void)setDelegate:(id<MapStateDelegate>)delegate {
}
How do I do the setter? Normally it would just be:
-(void)setDelegate:(id<MapStateDelegate>)delegate {
_delegate = delegate;
}
But since the variable is #dynamic instead of #synthesize, no _delegate is created. And #synthesize creates an error.
How should I be handling this?

Using #dynamic implies that the appropriate accessors will be created at run time. NSManagedObject does that for attributes of entities in the data model, but not for properties you declare. You could do this with some ObjC runtime wizardry (the APIs all exist, and are supported, so it's not what might be called a hack) but it's not trivial. (Using #dynamic would be fine if delegate were a transient property on the entity, but that would mean that the delegate would have to be one of the types supported by Core Data instead of any class implementing the protocol).
But there's hope! If you're using Xcode 7+ to generate NSManagedObject subclasses, it's safe to add your own properties in the subclass without fear of them being overwritten. You'd make the delegate property work by adding a #synthesize for it and then not adding your own setter. You don't have to provide one unless you need to do more than just set the property value.
If you do need a custom setter, modify the #synthesize to be something like
#synthesize delegate = _delegate;
(you don't have to use _delegate here, any valid name is fine)
Then add a setter like the one in your question that assigns to the synthesized name.

Related

How do I know if not declaring #synthesize will result in "use of undeclared identifier"?

In one of the assignments, I had to override the superclass's getter method for the game logic (so the method will get the subclass of the game logic instead of the original one).
CardGameViewController.h:
#import <UIKit/UIKit.h>
#import "Deck.h"
#import "CardGame.h"
#interface CardGameViewController : UIViewController
#property (nonatomic) NSUInteger startingCardCount; // abstract
#property (strong, nonatomic) CardGame *game;
- (Deck *)createDeck; // abstract
- (void)updateCell:(UICollectionViewCell *)cell usingCard:(Card *)Card; // abstract
#end
CardGameViewController.m:
#import "CardGameViewController.h"
...
// no #synthesize here, but works fine.
- (CardGame *)game
{
if (!_game) _game = [[CardGame alloc] initWithCardCount:self.startingCardCount
usingDeck:[self createDeck]];
return _game;
}
...
#end
SetCardGameViewController.m:
...
#interface TSSetCardGameViewController()
#property (strong, nonatomic) CardGame *game;
#end
#implementation TSSetCardGameViewController
#synthesize game = _game; // Compiler *will* complain if this line is commented out.
- (CardGame *)game
{
if (!_game) _game = [[SetCardGame alloc] initWithCardCount:self.startingCardCount
usingDeck:[self createDeck]];
return _game;
}
...
#end
Then I got "Use of undeclared identifier" for "_game". so I declared
#property (strong, nonatomic) CardGame *game;
But I got the same error, so I used "self.game" instead, which caused a bad access exception.
I couldn't find anything on Google, so I tinkered around until I found that this solves the problem:
#synthesize game = _game;
Now, my question is why. My understanding is the new version of Xcode does the synthesizing for me, unless I override both its getter and setter. I did override the getter, but not the setter, so Xcode technically should have included it automatically. The proof is that Xcode did not complain until I subclassed CardGameViewController and specifically overrode the getter method. (FYI neither CardGameViewController nor its subclass had a setter method for *game)
So I'm a little confused. Please help!
The problem here is that you have two versions of _game. Since the introduction of the new ABI (64-bit Mac and all iOS), each subclass can create its own ivars without tromping all over its superclass's ivars (even if they're named the same). And ivars created by #synthesize are private. Now hold that thought and let's see what's happening:
In your superclass, you declare a property that has a getter and setter (though you almost certainly don't mean to have a setter…) You override the getter. The compiler says "but you still want me to create a setter for you, so I'll create an ivar to match it."
In your subclass, you declare no new properties. You may think you do, but it's just the same property that comes from the superclass; it's not a new property. There's already a getter and setter in the superclass, so there's no need for the compiler to create an ivar.
You then reference an ivar that does not exist in your subclass. It only exists as a private ivar in the superclass. The compiler can't see that (and wouldn't let you access it even if it could).
The typical solution to this problem is, rather than overriding -game, just provide a class method called +gameClass and have it return the correct class to instantiate. (See +layerClass in UIView for an example of this pattern.)

Modern Objective-C and #synthesize

I'm trying convert my code to Modern Objective-C style. How i read here http://www.techotopia.com/index.php/The_Basics_of_Modern_Objective-C": "In the case of Modern Objective-C, however, the synthesis takes place by default, making the use of #synthesize declarations unnecessary. When using default property synthesize, instance variable properties are accessible from within code using the property name prefixed with an underscore."
However, I have:
Relationship.h
#interface Relationship : NSObject <NSCoding>
//...
#property(nonatomic, weak) Person* first;
//...
#end`
OtherRelationship.h
#import "Relationship.h"
#interface OtherRelationship : Relationship
#end
OtherRelationship.m
#import "OtherRelationship.h"
#implementation OtherRelationship
#synthesize first = _first;
- (void)foo
{
NSLog(#"%#", _first);
}
and it's working. But when i delete
#synthesize first = _first;
i get "Use of undeclared identifier '_first'" error. Does inheritanced variables doesn't work with autosynthesize or should i looking for problem elsewhere?
The backing ivar in the superclass is #private to the subclass. That is, the subclass may call self.first, but not _first. If you want to #synthesize again, use a different name because you can't refer to _first. For example, replace with #synthesize first = _ffirst; or just drop the #synthesize.

ios interface iVar vs Property

In an .h file, what is the difference between:
#interface ViewController : UIViewController
#property (strong, nonatomic) UIView* myView;
And
#interface ViewController : UIViewController{
UIView* myView;
}
The first one is the declaration of a property, whereas the second is only a ivar.
A property is the automatic declaration of a getter and a setter for an ivar, but if there is not ivar (like in your first example) the property will create the ivar too.
The main difference is that a #property is visible to other objects, and can be accessed by these using an instance of your class.
You can use #synthesize in your implementation file to automate definition de getter setter functions in your implementation.
Updated (following #Graham Lee's suggestion)
According to the visibility specifier for your instance variable (#protected / #private / #public) , the ivar can be used in your implementation file, subclasses or other classes. The implicit value is #protected, so in your example it will be visible to your implementation file and subclasses.

Quick inquiry about ivars scope [duplicate]

If you have a property in your public interface like the following
#interface MyClass : NSObject
#property(strong) NSString *myProp;
#end
And then synthesize it, in effect synthesizing the variable:
#implementation MyClass
#synthesize myProp = _myProp; // or just leave it at the default name..
#end
What is the visibility of the instance variable _myProp? That is, is this considered #public, #protected or #private? I'm guessing since MySubClass could inherit from MyClass then it would also get the properties (naturally), but would it also inherit the instance variable visibility?
What difference does it make if I put the property in a class extension? That would hide the property from subclasses, and I'm guessing the instance variable, too. Is this documented anywhere?
A synthesized ivar is completely invisible to all code that cannot see the #synthesize line (which basically means anything outside of the .m file). It's not #protected, it's not #private, it's simply unknown. With a #private ivar, other code trying to access it will be told that it's private, but with a synthesized ivar, other code trying to access it will be told that the field simply doesn't exist.
As a thought experiment, try imagining a situation where the ivar acted like it was #protected. You make a subclass, and you muck about with the ivar there. Now you go back to the superclass and change #synthesize myProp to #synthesize myProp=foo. What happens in the subclass? When the compiler processes the subclass, it cannot see the #synthesize line, so it would have no idea that you just changed the name of the ivar. In fact, it cannot even tell if the property is backed by an ivar at all, or if it's implemented with custom-written accessor methods. I hope it's obvious why this means that the subclass cannot possibly access the ivar, and neither can any other class.
That said, I'm not quite sure what the compiler does if you write code in the same .m file that tries to access the ivar. I expect it will treat the ivar as #private (since the compiler can, in fact, see that the ivar exists).
Also, none of this has any bearing on the runtime methods. Other classes can still use the obj-c runtime methods to dynamically look up your class's ivar list and muck about with it.
If it is declared in your interface it is virtually public when using the #property declarative. If you want to use #property declaratives and keep them property truly private, you should create a private category in your implementation.
MyClass.h
#interface MyClass : NSObject {
#private
NSObject* foo;
}
#end
MyClass.m
#import "ClassWithPrivateProperty.h"
#interface MyClass ()
#property (nonatomic,retain) NSObject* foo;
#end
#implementation MyClass
#synthesize foo;
// class implementation...
#end
A synthesized variable acts as if declared #private:
#interface Garble : NSObject
#property (copy) NSString * s;
#end
#implementation Garble
#synthesize s;
#end
#interface Bargle : Garble
#end
#implementation Bargle
- (void) useS {
NSLog(#"%#", s); // error: instance variable 's' is private
}
#end
I swear I've seen this in the docs, but I can't find it right now. Will update if I track it down.
You can create a dynamic property and indicate it to the compiler that its instantiation would be at run time.
And then in your subclass write your own getter or synthesize the property.
#interface BaseClass : NSObject
#property (nonatomic, strong) NSString *ThisWillBeSynthesizedInRespectiveSubclasses;
#end
#implementation BaseClass
#dynamic ThisWillBeSynthesizedInRespectiveSubclasses;
#end
In Sub classes
#interface Subclass : BaseClass
#end
#implementation Subclass
#synthesize ThisWillBeSynthesizedInRespectiveSubclasses = _ThisWillBeSynthesizedInRespectiveSubclasses;
#end
or you write your own setter / getter methods.
Hope this helps !
Other classes have access to everything that they #include. In other words, to everything that is inside your header.
If something appears only in your implementation file, other classes (including subclasses) don't know it exists. A synthesized property is like that. Other classes know only about the property (a property means a getter and a setter method) but they don't know anything about the inner implementation of its methods.
Note, that the access specifiers (public/private/protected) in obj-c are only a hint to the compiler that even if something appears in the header file, it can't be accessed. The runtime does not check it in any way.
What happens if you put it into a class extension? Note that a property is a set of two methods. You just hide the methods from every class which includes your class main header but not the class extension header.
We use this for example to declare a property as readonly and in class continuation we declare it as readwrite. Then, we can use the setter only from inside of the class.

What is the visibility of #synthesized instance variables?

If you have a property in your public interface like the following
#interface MyClass : NSObject
#property(strong) NSString *myProp;
#end
And then synthesize it, in effect synthesizing the variable:
#implementation MyClass
#synthesize myProp = _myProp; // or just leave it at the default name..
#end
What is the visibility of the instance variable _myProp? That is, is this considered #public, #protected or #private? I'm guessing since MySubClass could inherit from MyClass then it would also get the properties (naturally), but would it also inherit the instance variable visibility?
What difference does it make if I put the property in a class extension? That would hide the property from subclasses, and I'm guessing the instance variable, too. Is this documented anywhere?
A synthesized ivar is completely invisible to all code that cannot see the #synthesize line (which basically means anything outside of the .m file). It's not #protected, it's not #private, it's simply unknown. With a #private ivar, other code trying to access it will be told that it's private, but with a synthesized ivar, other code trying to access it will be told that the field simply doesn't exist.
As a thought experiment, try imagining a situation where the ivar acted like it was #protected. You make a subclass, and you muck about with the ivar there. Now you go back to the superclass and change #synthesize myProp to #synthesize myProp=foo. What happens in the subclass? When the compiler processes the subclass, it cannot see the #synthesize line, so it would have no idea that you just changed the name of the ivar. In fact, it cannot even tell if the property is backed by an ivar at all, or if it's implemented with custom-written accessor methods. I hope it's obvious why this means that the subclass cannot possibly access the ivar, and neither can any other class.
That said, I'm not quite sure what the compiler does if you write code in the same .m file that tries to access the ivar. I expect it will treat the ivar as #private (since the compiler can, in fact, see that the ivar exists).
Also, none of this has any bearing on the runtime methods. Other classes can still use the obj-c runtime methods to dynamically look up your class's ivar list and muck about with it.
If it is declared in your interface it is virtually public when using the #property declarative. If you want to use #property declaratives and keep them property truly private, you should create a private category in your implementation.
MyClass.h
#interface MyClass : NSObject {
#private
NSObject* foo;
}
#end
MyClass.m
#import "ClassWithPrivateProperty.h"
#interface MyClass ()
#property (nonatomic,retain) NSObject* foo;
#end
#implementation MyClass
#synthesize foo;
// class implementation...
#end
A synthesized variable acts as if declared #private:
#interface Garble : NSObject
#property (copy) NSString * s;
#end
#implementation Garble
#synthesize s;
#end
#interface Bargle : Garble
#end
#implementation Bargle
- (void) useS {
NSLog(#"%#", s); // error: instance variable 's' is private
}
#end
I swear I've seen this in the docs, but I can't find it right now. Will update if I track it down.
You can create a dynamic property and indicate it to the compiler that its instantiation would be at run time.
And then in your subclass write your own getter or synthesize the property.
#interface BaseClass : NSObject
#property (nonatomic, strong) NSString *ThisWillBeSynthesizedInRespectiveSubclasses;
#end
#implementation BaseClass
#dynamic ThisWillBeSynthesizedInRespectiveSubclasses;
#end
In Sub classes
#interface Subclass : BaseClass
#end
#implementation Subclass
#synthesize ThisWillBeSynthesizedInRespectiveSubclasses = _ThisWillBeSynthesizedInRespectiveSubclasses;
#end
or you write your own setter / getter methods.
Hope this helps !
Other classes have access to everything that they #include. In other words, to everything that is inside your header.
If something appears only in your implementation file, other classes (including subclasses) don't know it exists. A synthesized property is like that. Other classes know only about the property (a property means a getter and a setter method) but they don't know anything about the inner implementation of its methods.
Note, that the access specifiers (public/private/protected) in obj-c are only a hint to the compiler that even if something appears in the header file, it can't be accessed. The runtime does not check it in any way.
What happens if you put it into a class extension? Note that a property is a set of two methods. You just hide the methods from every class which includes your class main header but not the class extension header.
We use this for example to declare a property as readonly and in class continuation we declare it as readwrite. Then, we can use the setter only from inside of the class.