I was doing some research on the differences #dynamic and #synthesize, so I make a small (simple) example:
#interface Classe : NSObject
#property (nonatomic) int value;
#end
#implementation Classe
#synthesize value;
#end
int main(int argc, const char * argv[]) {
#autoreleasepool {
Classe *cl = [[Classe alloc] init];
cl.value = 50;
NSLog(#"%d",cl.value);
}
return 0;
}
From what I understand with this my example, is that the 'synthesize' creates behind the scenes getters and setters methods, and as we have seen above I only do cl.value = 50;.
Now, let's talk about #dynamic, I hear that
is merely a way to inform the system not to generate getters/setters
for the thing, that you (or someone else) will provide them for you.
Okay, if in my example above I change the #synthesize to #dynamic the application will give error returning the following message:
unrecognized selector sent to instance 0x10010eeb0
This was because it was said that the compiler does not create the getters and setters methods, knowing this, how could I create the getters and setters methods manually?
Well, you simply do. If your property has a name
#property (nonatomic) int value;
Then in your implementation you just define methods:
-(int)value {
//your getter here
}
-(void)setValue:(int)newValue {
//Your setter here
}
#dynamic value; tells compiler that it should NOT make default accessors.
But you don't need #dynamic to do it. You can just write a getter and a setter. You might need #synthesize though. Because if you specify your own getter and setter, the compiler won't generate an instance variable (_value) for you. To make it do it (if you need it), you will need #synthesize.
More about it: SO: Getters, setters and underscore property names.
Related
I am trying to re-struct my project code with an inheritance style, what is the best practice for how to inherit property from parent class and override setter and getter?
I give the demo code, in the demo, ChartModel is a base class in a ChartViewController, and LineChartModel is a sub class of ChartModel in LineChartViewController.
I want to override the setter and getter of LineChartModel *dataModel in sub view controller. Please include any #synthesize and protected instance variable, or if it is automatically generated by compiler, please mark. Thank in advance.
// ChartModel.h
#interface ChartModel : NSObject
-(BOOL)hasData;
#end
// LineChartModel.h
#interface LineChartModel : chartModel
-(void)getLineColor;
#property (nonatomic, strong) NSArray* dataArray;
#end
// ChartViewController.h
#interface ChartViewController: UIViewController
#property (nonatomic, strong) ChartModel *dataModel;
-(void)updateUI;
#end
// ChartViewController.m
#implementation ChartViewController
-(void)updateUI {
if ([self.dataModel hasData]) {
[self.view setHidden:NO];
} else {
self.view.hidden = YES;
}
// setter and getter here
#end
// LineChartViewController.h
#interface LineChartViewController : ChartViewController
// pay attension here, same name but a sub class of chartModel
#property (nonatomic, strong) LineChartModel *dataModel;
#end
// LineChartViewController.m
#implementation LineChartViewController
//override dataModel setter here
//override dataModel getter here
#end
Technically, the only thing you need in the implementation of LineChartViewController is:
#dynamic dataModel;
That tells the compiler that the getter and setter will be supplied in some way it can't immediately see. In actuality, they will be supplied by the superclass.
However, that allows for a problem. A LineChartViewController is-a ChartViewController. That means that an instance of LineChartViewController can be passed to a method or function which is declared to take a ChartViewController and that method/function is entitled to do anything to it that is allowed by the interface of ChartViewController. That includes assigning an instance of ChartModel (not LineChartModel) to its dataModel property. Presumably, LineChartViewController will break if its dataModel property is not a LineChartModel.
In technical terms, your design violates the Liskov substitution principle.
It's not a fix for the design issue, but you can catch the problem at run time if it happens, by implementing an override of the setter like this:
- (void) setDataModel:(LineChartModel*)dataModel
{
if (dataModel && ![dataModel isKindOfClass:[LineChartModel class]])
{
NSString* reason = [NSString stringWithFormat:#"%# is not a valid dataModel for LineChartViewController; it must be a kind of LineChartModel", dataModel];
[[NSException exceptionWithName:NSInvalidArgumentException reason:reason userInfo:nil] raise];
}
[super setDataModel:dataModel];
}
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.
Eg:
//Myclass.h
#property(nonatomic, strong) NSString *name;
//MyClass.m
//#synthesize name = _name
So I know that we don't need to use #synthesize any more from iOS6+. The compiler automatically creates getters and setters for me.
But I don't understand is when to use self.name = #"Testing" and when to use _name = #"Testing"?
Should _name = #"Testing" be ever used?
If yes, when? When should an iVAR be used at all?
Also if i want to write my own getter and setter do i need to write #synthesize or can i just write my getter and setter?
Thanks for your help!
Normally, you only use instance variables in init methods, getters and setters, and dealloc. There are exceptions of course, but this is a good rule of thumb.
If you write both your own getter and setter (or in the case of a readonly property and you write the getter), you have to synthesize your property yourself. In all other cases, the property is auto-synthesized.
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.
I am having following condition:
#interface MyClass:NSObject
#public NSString *str;
#end
#implementation
-(id)init{
}
#end
Now I want to access str variable outside MyClass in Other Class, (1) Using MyClass Object (2) without using MyClass Object, How can I achieve that?
You can call using this:
MyClass *a;
a.str;
Without the object, you cannot call an instance variable. However, you can call static method with this declaration:
#interface MyClass:NSObject
+ (void)doX;
#end
#implementation
+ (void)doX {
// do whatever
}
then in another class you just need to call:
[MyClass doX];
However, let a public instance variable is not a good practice. The reason is that it will let any class, methods change that instance variable without your control. For example, they can set the NSString *str to nil and then nobody can call anything, or they may forget to do memory management when they call.
A better practice for public variable is using #property
For example, your string should be declared like:
#property (nonatomic, retain) NSString * str;
and then in the implementation:
#implementation MyClass
#synthesize str;
The good thing about property is that compiler will generate gettter and setter methods for you and those setters will handle memory correctly for you.
More about properties here
Sigh, i realise this post is LONG dead but I believe The above answer is incorrect.
well the first bit.
Please see the link below.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocObjectsClasses.html#//apple_ref/doc/uid/TP30001163-CH11-SW1
for the above interface to work, you NEED to declare a property for use outside of its class
Because the instance variable it is not visible outside its class.
well; You don't NEED to. Doing something like MyClass->str is valid.
Please see this example
#interface Foo : NSObject {
#public NSInteger publicMember;
#private NSInteger aproperty;
}
#property (assign) NSInteger aproperty;`
then the calling class
Foo *f = [Foo new];
f.aproperty = 90;
//f.publicMember = 100; property 'publicMember' not found of type Foo *
f->publicMember = 100;
But as the above post said, you should always use #properties because if var public was a string, you are not retaining the string in any way.