#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface Employee : NSManagedObject
#property (nonatomic, retain) NSString* name;
#property (nonatomic, retain) NSNumber* pin;
-(id) initWithName:(NSString*)name Pin:(NSNumber*)pin;
#end
#implementation Employee
#dynamic name;
#dynamic pin;
-(id) initWithName:(NSString*)iname Pin:(NSNumber*)ipin{
self = [super init];
if(self){
name = iname;
pin = ipin;
}
return self;
}
#end
Compiler says name and pin are undeclared in the .m file. What am I doing wrong?
Putting self.name and self.pin works, but could someone tell if this is proper or why this works? etc.
Thank you in advance for help.
You wrote this in your initializer:
name = iname;
Since you don't have a local variable named name, the compiler looks for an instance variable named name, or a static or global variable named name. You don't have an instance variable named name, or a static or global either. You have a property named name. To set the property, you need to either use “dot notation”:
self.name = iname;
or you need to send a setName: message:
[self setName:iname];
Both of these compile to exactly the same code.
Note that since your superclass is NSManagedObject, I assume Employee is an entity defined in your Core Data model with attributes name and pin. If so, using #dynamic is correct. If those are not attributes defined in your model, you should probably be using #synthesize (or omitting both #dynamic and #synthesize and letting the compiler auto-synthesize the properties).
Related
I have a class below:
#interface Person : NSObject {
NSString *_firstname;
}
#property NSString *firstName;
#end
#implementation Person
#synthesize firstname;
#end
This will declare three variables: firstname, self.firstname and _firstname
What is the difference between the three variables and how do you using with each case?
In modern Objective-C you don't need to create instance variable if you already synthesizing properties.
From what you write it appears that you are confusing properties and ivar.
Properties create getters and setters to your ivars, but they are not ivars, they are methods that access you ivars to set or get their values.
Your class can be sum up like that:
#interface Person : NSObject
#property NSString *firstName;
#end
#implementation Person
#end
At compile time this will ensure that you can access your ivar using methods and name your ivar as _firstName.
Dot notation create access to properties so self.firstName (using ARC and default property option -nonatomic,strong-)calls that method
- (NSString*)firstName
{
return _firstName;
}
While calling self.firstName = #"foo"; calls:
- (void) setFirstName:(NSString*)name
{
if (_firstName == name) {
return;
}
_firstName = name;
}
Underlining implementation could be a little different.
The first one NSString *_firstname; is an instance variable. The #property is a property which is syntesized (you don't have to manually synthesize properties in modern Objective-C). When you declare a property you can access its instance variable with _propertyName or with self.propertyName.
It is up to you whether you declare your variables as instance variables or as properties but it is more common and suggested to declare them as properties (using properties you can have access to getters and setters, which means that you can run code before the value of the property will be set or will be read).
You can chain instance with property using
#interface Person : NSObject {
NSString *_firstname;
}
#property NSString *firstName;
#end
#implementation Person
#synthesize firstName = _firstname;
#end
Both pointers are pointing same instance now.
I am practicing inheritance in Objective-C and this is my Person parent class
// This is Person.h
#interface Person : NSObject
#property(nonatomic, strong) NSNumber *age;
#property(nonatomic, strong) NSString *race;
-(instancetype)init;
-(instancetype)initWithAge:(NSNumber*)age andRace:(NSString*)race;
#end
This is what I'm trying to do in my Student class
// This is Student.h
#import "Person.h"
#interface Student : Person
#property(nonatomic, strong) NSString *classification;
#property(nonatomic, strong) NSString *major;
#end
And
// This is Student.m
#import "Student.h"
#import "Person.h"
#implementation Student
-(instancetype)init
{
return [self initWithClassification:#"Freshman" andMajor:#"Computer Science"
andAge:[[NSNumber alloc] initWithInt:20] andRace:#"Caucasian"];
}
-(instancetype)initWithClassification:(NSString*)classification andMajor:(NSString*)major
andAge:(NSNumber*)age andRace:(NSString*)race
{
self = [super init];
if (self)
{
_classification = classification;
_major = major;
_age = age;
_race = race;
}
return self;
}
#end
The compiler is not liking my doing
_age = age;
_race = race;
Use of undeclared identifier _age did you mean age? Can someone tell me where I went wrong? Thank you.
When you declare a property like that, clang will automatically #synthesize it for you (i.e it will create a getter and setter), but synthesized properties are not visible to subclasses, you have different alternatives to make it working.
You can synthesize the ivar in the interface of the subclass
#synthesize age = _age;
Or you can declare the ivar protected on the interface of the superclass, so that will be visible on the subclasses.
#interface Person : NSObject {
#protected NSNumber *_age;
}
Or you can use self.age = ... on your subclass, without using the ivar at all.
Since clang compiler now auto-synthesise properties you don't have, in most cases, to synthesise your properties.
Objective-C Autosynthesis of Properties
Clang provides support for autosynthesis of declared properties. Using
this feature, clang provides default synthesis of those properties not
declared #dynamic and not having user provided backing getter and
setter methods. __has_feature(objc_default_synthesize_properties)
checks for availability of this feature in version of clang being
used.
But in some cases (some examples are in this question) you should explicitly synthesise them.
In this case, to solve your problems you should just add:
#synthesize age = _age;
#synthesize race = _race;
to your code, and you'll be fine.
The subclass has access to the property, but not the backing variable. So you should set it with
self.age = age;
I'm new to objective-C, so apologies if this is repeated somewhere. I have a category(?) that is something like:
inside SomeClass.h:
#interface SomeClass (SomeCategory) <SomeDelegate>
#property (nonatomic, retain) id somePublicProperty;
#property (nonatomic, retain) id someProperty; // <-- i want to move this to "private"
#end
and now in my SomeClass.m, all i have is:
#implementation SomeClass (SomeCategory)
// dynamic setters/getters here for someProperty.
#end
I think the someProperty is public. how do i make this "private"? (in other words, how do i syntactically put this in the .m file? i tried to use
#interface SomeClass (SomeCategory) {
#property (nonatomic, retain) somePrivateProperty;
}
#end
but it just complains that i have duplicate definition of the category. how do i do this correctly?
In your .h file, you should not give the category. Just use:
#interface SomeClass : SomeBaseClass < SomeDelegate>
#property (nonatomic, retain) id somePublicProperty;
#end
In your .m file, define your private property inside a class extension:
#interface SomeClass ()
#property (nonatomic, retain) id somePrivateProperty;
#end
A class extension is not a like category in that it allows you to extend an interface as well as add new storage to your class.
In a class category, you can define new properties, but no storage will be allocated for it, so you have to do it by hand:
#interface SomeClass (SomeBaseCategory)
#property (nonatomic, retain) id somePrivateProperty;
#end
#implementation SomeClass {
id _somePrivateProperty;
}
- (void)setSomePrivateProperty:(id)property {
_somePrivateProperty = property;
}
- (id)somePrivateProperty {
return _somePrivateProperty;
}
#end
Otherwise your app will crash.
In any case, keep in mind that given the dynamic nature of Objective-C, your property will never be fully private, since you can always send a message to an Objective-C object through objc_msgsend and thus set or read the property value.
EDIT:
If you do not have the source code for a class implementation, you cannot define a class extension (as per source linked above).
In this case, you could use object association to define properties.
Just add the category definition in the .m file OUTSIDE the implementation block
Like so:
#interface MyClass (MyCategory)
#property (assign) BOOL myPrivateProperty;
#end
#implementation MyClass
...
#end
Categories are best used for adding capability to code you do not own and cannot change. Adding properties via categories is not impossible, but is much more difficult.
Class Extensions are best used for keeping properties your object needs, but are not intended to be public.
If you do truly need to add properties to this object, the way to do it is with the Objective-C runtime's associated objects
There's an excellent writeup of when/how to use them here
From Xcode 4.4 onwards has Default Synthesis Of Properties. It generates this automatically:
#synthesize name = _name;
source
And from source2
readwrite vs readonly determines whether a synthesized property has a synthesized accessor or not (readwrite has a setter and is the default, readonly does not).
Therefore, I've concluded that #synthesize name = _name; is not required for readwrite but it's needed for readonly
However, in Apple's spritekit Adventure code (adventure code download link), APAAdventureScene.m:
"heroes" (readwrite) is synthesize in the example. If it's not synthesize it will give this error: Use of undeclared identifier '_heroes'
Is #synthesize required for readwrite property, I'm confuse?
Thank you
#interface APAAdventureScene () <SKPhysicsContactDelegate>
...
#property (nonatomic, readwrite) NSMutableArray *heroes; // our fearless adventurers
#property (nonatomic) NSMutableArray *goblinCaves; // whence cometh goblins
...
#end
#implementation APAAdventureScene
#synthesize heroes = _heroes;
- (id)initWithSize:(CGSize)size {
...
_heroes = [[NSMutableArray alloc] init];
_goblinCaves = [[NSMutableArray alloc] init];
...
}
- (void)updateWithTimeSinceLastUpdate:(CFTimeInterval)timeSinceLast {
// Update all players' heroes.
for (APAHeroCharacter *hero in self.heroes) {
[hero updateWithTimeSinceLastUpdate:timeSinceLast];
}
// Update the caves (and in turn, their goblins).
for (APACave *cave in self.goblinCaves) {
[cave updateWithTimeSinceLastUpdate:timeSinceLast];
}
}
#end
#synthesize isn't required for anything anymore as long as you are using a modern LLVM compiler (the default for over 1 year now).
readwrite is the default so both properties are read/write. There is NO reason for the #synthesize line in the posted code.
The only exception to this is if you explicitly provide both the "setter" and "getter" for a readwrite property. Then the ivar is not automatically generated. For a readonly property the ivar isn't generated if you supply an explicit "getter".
I am attempting to create an abstract class and inherit some of its properties in a subclass. If I leave the properties in the abstract class' header file, all of the properties are accessible. The problem is that the instance of the subclass can also access those properties, which is not always desirable in my case.
For instance, I have a delegate in my abstract class that sends down button presses to its sub class. I realize that this may not be the best way of structuring inheritance, so other suggestions are welcome. However, I would still like to know how my subclass can inherit some properties from its superclass without making all of those properties available in its instance. Thanks in advance!
Here is some example code below:
#interface AbstractClass : UIView
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
…
#protocol ButtonDelegate
#required
- (void) buttonWasPressed;
#end
…
#interface SubClass() <ButtonDelegate>
- (id)init {
self = [super init];
if (self) {
self.buttonDelegate = self;
}
return self;
}
-(void) buttonWasPressed {
[self doSomething];
}
…
#implementation ViewController
- (void)viewDidLoad {
SubClass *subClass = [[SubClass alloc] init];
subClass.buttonDelegate = self; // THIS IS NOT DESIRABLE
}
Do like UIGestureRecognizer does.
All public properties and methods goes into UIGestureRecognizer.h
All protected properties and methods goes into UIGestureRecognizerSubclass.h.
Only import this in the *.m-files. Never include it in any public header.
All private properties and methods goes into *.m-files. Use the #interface ClassName ()
Example https://gist.github.com/hfossli/8041396
how to my subclass can inherit some properties from its superclass
without making all of those properties available in its instance
What is the problem with this?
#import <Foundation/Foundation.h>
#interface Animal : NSObject
{
#protected
NSString *name; // default access. Only visible to subclasses.
}
#end
#implementation Animal
-(NSString*)description {
return name;
}
#end
#interface Cow : Animal
#end
#implementation Cow
-(id)init {
self=[super init];
if (self){
name = #"cow";
}
return self;
}
#end
int main(int argc, char *argv[]) {
#autoreleasepool {
Cow *cow = [Cow new];
NSLog(#"%#", cow); // prints the name through internal access
// error accessing from the outside: NSLog(#"%#", cow.name);
Animal *animal = [Animal new];
// error accessing from the outside: NSLog(#"%#", animal.name);
}
}
Maybe I misunderstood the question, you say
Creating properties only visible to subclass in Objective-C
and then
The problem is that the instance of the subclass can also access those
properties
Which one is it?
Create an empty category on top of your implementation file (.m):
#interface AbstractClass()
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
#end
In that way, your subclass will inherit and can access that property, but not other external classes because it's not in the header.
I don't think there is any way to achieve this using property declaration.
Either a property be visible for all (declared in .h file) or it will be invisible for all (declared in .m file using category)
I guess one way is declaring public/protected variable in .h file class declaration:
#interface AbstractClass : UIView {
...
id<ButtonDelegate>buttonDelegate;
...
}
#end
I am not sure about this, but give a try.
I see one approach that can fit your problem, however, it is pretty rude. Use Antonio's suggestion and create the private category with the property. As you've mentioned, it's scope is limited to the .m file. So you can put your subclasses into that file. This will be hard to read the code if subclasses are huge, but this is the only way for you as far as I understand.
EDIT: well, I have another solution. Copy
#property (nonatomic, strong) id<ButtonDelegate>buttonDelegate;
to all your subclasses. This will give you a warning about the absence of the property's #synthesize, but should work. I'd prefer this, if subclasses wont be changed or added often.
Let me describe how it would work.
We add a property into the Abstract class, and it is hidden for all (even for subclasses):
// .m file
#interface Abstract ()
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
#implementation Abstract
#synthsize buttonDelegate;
#end;
But due to runtime features of Objective-C we still can call for that property, and there will not be any runtime error, only compiler warning.
To get rid of that warning and to add an ability to autocomplete, we add property without #synthsize into all subclasses:
#interface MySubclass : Abstract
#property (nonatomic, strong) id<ButtonDelegate> buttonDelegate;
#end
This will tell the compiler that there is such a property somewhere. There will be also one warning about the absence of #synthesize, but Xcode will still could autocomplete if you write something like
MySubclass *subclass = ...
subclass.butto...
It can not be done. There is no private or protected in objective-c. Stuff declared in the .m file "private" interface is only visible to that class and not in any subclass. Also you can always use your "private" properties/methods from outside if you want, although it would be bad practice to do so.