#dynamic property in Objective C - ios

I'm trying to implement a Dynamic property in my project
This is my code.
MyClass.h
#interface MyClass : UIView
#property (strong, nonatomic) NSString *name;
#end
MyClass.m
#implementation MyClass
#dynamic name;
-(void)setName:(NSString *)name{
self.name = name;
}
#end
But when I run my app has crashed.
When I use an ivar had this error.

A property is just a bundle of two methods: a getter and a setter. So, when you write
#property (strong, nonatomic) NSString *name;
what you are really saying is
- (NSString *)name;
- (void)setName:(NSString *)name;
After that, each time the compiler encounters an expression of the form obj.name, it translates it to [obj name]. And each time you see a statement like obj.name = #"hello";, the compiler translates it to [obj setName:#"hello"].
The next thing is you have to make sure the property behaves properly. You have many options:
Write getters and setters manually, referring to an iVar
Synthesize getter and setter
Autosynthesize getter and setter
Write custom getters and setters
Use #dynamic to avoid compile time warnings, because you intend to do runtime magic. (Really, that's not what you want to do, because you need to understand the basics first.)
Write getters and setters manually, referring to an iVar
#interface MyClass : UIView {
NSString *_name;
}
#property (strong, nonatomic) NSString *name;
#end
and in the implementation
#implementation MyClass
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = name;
}
#end
Synthesize getter and setter
The last section is basically equivalent to this
#interface MyClass : UIView {
NSString *_name;
}
#property (strong, nonatomic) NSString *name;
#end
#implementation MyClass
#synthesize name = _name;
#end
Autosynthesize getter and setter
In practice, you would just use "autosynthetisation".
#interface MyClass : UIView
#property (strong, nonatomic) NSString *name;
#end
#implementation MyClass
#end
This means,
if you just declare a property
don't call #synthesize or #dynamic
don't implement any custom getter and setter
the code above will just create an iVar named _name and a getter and setter that looks exactly like the one in the first example.
This means that the the first two and this sections are equivalent, because they produce the same code.
Write custom getters and setters
This is what the term "dynamic property" really means. For example, you may want the name to be always uppercase. So you may write a property like this.
#interface MyClass : UIView {
NSString *_name;
}
#property (copy, nonatomic) NSString *name;
#end
#implementation MyClass
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = [name uppercaseString];
}
#end
(in the code above, I changed strong to copy - don't worry, this is just a comment anyways. And it's a true one, because the uppercaseString will never be the same, it will always be a copy of the original.)
This is maybe the only really interesting case! For example, this kind of property is what UIKit uses all the time, e.g. the text property of UILabel is a dynamic property like that. It doesn't just set some iVar, but it also makes sure that the visible text on the screen changes too.
#dynamic properties
they are really tricky to get right, and most of the time they are not worth the hassle IMHO.
Note: I simplified some things and left out details which are only detectable when using objc runtime inspection APIs

This StackOverflow answer: https://stackoverflow.com/a/1160545/7833793 does a good job of explaining what the differences between #synthesize and #dynamic are. Typically you use #dynamic if you're delegating the task of implementing the accessors (get, set). It seems to me like you would want to use #synthesize here. But with modern objective c, you shouldn't even need to specify and the iVar will be created for you automatically.
i.e.:
MyClass.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
#interface MyClass : NSObject
#property (strong, nonatomic) NSString *name;
#end
NS_ASSUME_NONNULL_END
MyClass.m
#import "MyClass.h"
#implementation MyClass
- (void)setName:(NSString *)name {
_name = name;
}
#end

Your solution leads to recursion, you are getting crash since you are not using ivar in setter, try this instead:
-(void)setName:(NSString *)name{
_name = name;
}

Related

No automatic underscore ivar in Xcode 5.1.1

I just noticed that, for some reason, I don't seem to have automatically created underscore iVars in my iOS 7 project, and I wonder why that is. My setup:
MyClass.h
#property (readonly) NSNumber *aNumber;
MyClass.m
#interface MyClass ()
#property (readwrite, strong) NSNumber *aNumber;
#end
#implementation MyClass
(...)
- (NSNumber *)aNumber {
return _aNumber;
}
- (void)setANumber:(NSNumber *)aNumber {
_aNumber = aNumber;
}
#end
This results in Use of undeclared identifier: '_aNumber'.
Why is that so? I thought that underscore iVars are always automatically synthesized? Is it because of the class extension I use? If I put in #synthesize aNumber = _aNumber; it (obviously) works.
There is one exception to the automatic synthesize rule.
If you override both the getter and the setter of a property then you will have to manually synthesize the property.
This has been the case ever since auto synthesis came in.
Just add the #synthesize line and it will be fine.

How to make an immutable readonly property in the header file (.h), a mutable readwrite property in implementaion (.m)

I have an object that holds a dictionary JSONData. From the header file, and to the other classes that'll access it, I want this property to only be read-only and immutable.
#interface MyObject : NSObject
#property (readonly, strong, nonatomic) NSDictionary *JSONData;
#end
However, I need it to be readwrite and mutable from the implementation file, like this, but this doesn't work:
#interface MyObject ()
#property (readwrite, strong, nonatomic) NSMutableDictionary *JSONData;
#end
#implementation MyObject
// Do read/write stuff here.
#end
Is there anything I can do to enforce the kind of abstraction I'm going for? I looked at the other questions and while I already know how to make a property readonly from .h and readwrite from .m, I can't find anything about the difference in mutability.
You need a separate private mutable variable in your implementation. You can override the getter to return an immutable object.
#interface MyObject () {
NSMutableDictionary *_mutableJSONData;
}
#end
#implementation MyObject
// ...
-(NSDictionary *)JSONData {
return [NSDictionary dictionaryWithDictionary:_mutableJSONData];
}
// ...
#end
No need to implement the setter, as it is readonly.

Associative references with NSInteger

I'm developing an iOS 5.0+ app and I'm creating a Category for an UIButton:
#interface UIButton (NotificationBall)
#property (nonatomic, assign) NSInteger type;
#property (nonatomic, assign) NSInteger index;
#end
And its implementation:
#import "UIButton+NotificationBall.h"
#implementation UIButton (NotificationBall)
#dynamic type;
#dynamic index;
#end
Searching on internet I've found this question, but I haven't found any examples with NSInteger.
Do I need to use NSNumber instead of NSInteger?
If I use, NSNumber, what do I have to do?
Only Objective-C objects can be set as
associated objects, scalars cannot be used directly.
So you could declare the property as
#property (nonatomic, strong) NSNumber *type;
and directly use the code from the answer https://stackoverflow.com/a/5500525/1187415
that you referenced to.
Or you keep the NSInteger property, and wrap/unwrap it to NSNumber
in the getter/setter method like this:
-(void)setType:(NSInteger)type
{
objc_setAssociatedObject(self, &UIB_TYPE_KEY, #(type), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSInteger)type
{
return [objc_getAssociatedObject(self, &UIB_TYPE_KEY) integerValue];
}
Remark: "type" and "index" are quite common names. You should consider prepending the property names with some prefix, to
avoid a possible name collision with existing properties of UIButton.

Do I need variable and property at the same time?

I'm new in iOS development, and have trouble in understanding of some cases.
My question is do I need variable and property at the same time?
For example I saw code like this:
#import <Cocoa/Cocoa.h>
#interface Photo : NSObject {
NSString* caption;
NSString* photographer;
}
#property (retain) NSString* caption;
#property (retain) NSString* photographer;
#end
But, as I know, if I delete variables caption and photographer code still will work:
#import <Cocoa/Cocoa.h>
#interface Photo : NSObject
#property (retain) NSString* caption;
#property (retain) NSString* photographer;
#end
So, please explain the difference of using first one and second.
Thanks, for any advices!
Variables inside the {} parenthesis are instance variables. They're accessible only to the class.
#property defines a few different things denoted by the (options).
Most people use #property to convenience methods inside your .m and .h files. For example
#property (strong) NSString *string;
Creates two methods inside your .h and .m file, invisible to you though, called:
-(NSString *)string; //returns the string object
-(void)setString:(NSString *)string;
So what it does is improve readability and helps reduce a lot of boiler plate code.
It's no longer necessary to define the instance variable inside the {} parenthesis now.
If you need to have the instance variable set to a different name you can put a
#synthesize string = _string;
Since you're new at this Ill add some bonus stuff for you to think about.
self.string = #"string"
May not be an equivalent call as
string = #"string"
If you have #property (strong) NSString *string; and #synthesize string;
The reason for this is setting the string via self.string is using the method implementation to set the string and may be overridden like this:
-(void)setString:(NSString *)str{
string = [NSString stringWithFormat:#"%#.jpg", str];
}
So self.string = #"hello" would be #"hello.jpg" where as string = #"hello" is just "hello"
Also self.string = #"string"; is much the same as [self setString:#"string"];
For clarification on what #property(strong)NSString *string does
inside the .h adds:
{
NSString *_string;
}
-(void)setString:(NSString *)string;
-(NSString *)string;
inside .m:
-(void)setString:(NSString *)string{
_string = string;
}
-(NSString *)string{
return _string;
}
So there's no need to call #synthesize unless you want to rename the iVar into something else
#synthesize string = wibblyWobblyTimeyWimey;
so in the .h it would be
{
NSString *wibblyWobblyTimeyWimey;
}
inside the .m
-(void)setString:(NSString *)string{
wibblyWobblyTimeyWimey = string;
}
-(NSString *)string {
return wibblyWobblyTimeyWimey;
}
If you're using Xcode 4.6.x, and you've installed the command-line tools with Clang 4 or higher, you can take advantage of 'auto-synthesized' properties.
#interface Photo : NSObject
#property (retain) NSString* caption;
#property (retain) NSString* photographer;
#end
Will give you the instance variables _caption and _photographer. So no, you really don't need to declare instance variables in most cases. If you're using ARC, it would only make sense to use properties.
Here is what that code should look like if you're using ARC:
#interface Photo : NSObject
#property (strong) NSString* caption;
#property (strong) NSString* photographer;
#end
Also, generally it's a good idea to specify the nonatomic attribute. Not doing so will mean that the accessors that clang will generate will be using locks:
#interface Photo : NSObject
#property (strong, nonatomic) NSString* caption;
#property (strong, nonatomic) NSString* photographer;
#end
No you do not. The variable in the {} are private members, not accessible to classes that inherit this header file, whereas properties can be access, read, and written, by inheriting classes.
But this is not always the case. In certain cases, (like delegates), both are required.

Difference in variable declarations in Cocoa Class

I'm new to iOS development and I've been seeing the following in several tutorials as well as when Xcode autogenerates code for me when subclassing one of my classes. Let's say I have the following .h and .m files
#import <UIKit/UIKit.h>
#interface Class : NSObject {
NSArray *_infos;
NSString *_context;
}
#property (nonatomic, retain) NSArray *infos;
#property (nonatomic, retain) NSString *context;
#end
#import "Class.h"
#implementation Class
#synthesize infos = _infos;
#synthesize context = _context;
#end
And then consider this which is how I would normally do it:
#import <UIKit/UIKit.h>
#interface Class : NSObject {
NSArray *infos;
NSString *context;
}
#property (nonatomic, retain) NSArray *infos;
#property (nonatomic, retain) NSString *context;
#end
#import "Class.h"
#implementation Class
#synthesize infos;
#synthesize context;
#end
What is the difference? From the notation I can just infer that they're just declaring the variables as private, but how does it work? If I'm correct.
It's a silly naming convention. Use it if you want to, leave it if you don't.
The advantage is that a method argument/local variable named context does not conflict with the ivar _context. It has little to do with privacy, since you can just specify #private to make the ivars private (or just #synthesize them in the first place).
The disadvantage is that you have underscores everywhere, and underscores are occasionally a bit special in C (though an underscore followed by a lowercase letter is only reserved in file scope, so you should be fine provided the ivar starts with a lowercase letter...). Where necessary, I stick an underscore at the end which feels less dirty.
Sidenote: A few people use method names beginning with an underscore to mean "private", but this convention is reserved by Apple.
The only difference is the name of the ivars ("instance variables") holding the properties.

Resources