Objective-C releasing a property declared in a category? - objective-c

I have a category on an existing class that adds a property and a few methods to the class.
#interface AClass (ACategory) {
NSString *aProperty;
}
#property (nonatomic, retain) NSString *aProperty;
#end
In the implementation file, I want to release this property when the object is deallocated. However, if I declare dealloc in this class, it will override the dealloc from the original class from what I understand. What then is the proper way to release this aProperty when the object is deallocated?
#implementation AClass (ACategory)
#synthesize aProperty;
- (void)dealloc {
[aProperty release];
// this will skip the original dealloc method from what I understand
[super dealloc];
}
#end

Well, this is a little problematic, since your code is wrong.
You can't declare instance variables in a category; using the latest Objective-C ABI, you can declare new instance variables within a class extension (#interface AClass () {//...), but that is different from a category (#interface AClass (ACategory)).
Even if you could, the syntax for instance variable declaration is that they be enclosed in curly braces after the #interface line.
You can declare a property in a category, but you'll have to define its storage without using a new instance variable (hence, #dynamic instead of #synthesize).
As to your actual question, you can't call the original implementation of an overridden method unless you use method-swizzling (facilitated by runtime functions like method_exchangeImplementations). I recommend against doing this anyway; it's really frightening and dangerous.
Update: Explanation of Instance Variables in Class Extensions
A class extension is like a category, but it is anonymous and must be placed within the .m file associated with the original class. It looks like:
#interface SomeClass () {
// any extra instance variables you wish to add
}
#property (nonatomic, copy) NSString *aProperty;
#end
Its implementation must be in the main #implementation block for your class. Thus:
#implementation SomeClass
// synthesize any properties from the original interface
#synthesize aProperty;
// this will synthesize an instance variable and accessors for aProperty,
// which was declared in the class extension.
- (void)dealloc {
[aProperty release];
// perform other memory management
[super dealloc];
}
#end
So, a class extension is useful for keeping private instance variables and methods out of the public interface, but will not help you add instance variables to a class over which you haven't control. There is no issue with overriding -dealloc, because you just implement it like you normally would, whilst including any necessary memory management for the instance variables you introduced within the class extension.
Please note that this stuff works only with the latest 64-bit Objective-C ABI.

As an aside, you can use associated references to "simulate the addition of object instance variables to an existing class".
Essentially, you can add an associated object as below:
static void* ASI_HTTP_REQUEST; // declare inside the category #implementation but outside any method
// And within a method, init perhaps
objc_setAssociatedObject(self,
&ASI_HTTP_REQUEST,
request,
OBJC_ASSOCIATION_RETAIN);
And release the associated object by sending 'nil':
// And release the associated object
objc_setAssociatedObject(self,
&ASI_HTTP_REQUEST,
nil,
OBJC_ASSOCIATION_RETAIN);
The Apple documentation is here.
It took me a while to find, so I hope that it helps someone.

Related

Objective-C: Overriding Getter & Setter with Instance Variable (using _) [duplicate]

This question already has answers here:
Error accessing generated ivars when I override setters and getters in Modern Objective-C
(3 answers)
Closed 5 years ago.
I'm learning the Swift programing language and during this I sometimes get in touch with the old Objective-C programming language and its code.
I'm an absolutely beginner and therefore I have some question for better understanding the Setter and Getter.
So, I know that I can create an instance variable through curly braces in the .h file but normally I use properties. These properties are backed by an instance variable and offer automatically a Getter and Setter Method.
Example:
Vehicle .h file:
#interface Vehicle : NSObject
#property int myProperty;
#end
Because I created this property I don't have to declare a Getter and Setter method in the vehicle.m file because they are automatically created by the compiler. So I can create a vehicle-object, set and get the value.
Example
main.m
Vehicle *myvehicle = [[vehicle alloc] init];
[myvehicle myProperty] // myvehicle.myProperty
[myvehicle setMyProperty : 10] // myvehicle.myProperty = 10;
Now I read that it is possible to override the automatically created Getter and Setter method of my created property "myProperty". When declaring my own version of the Getter and Setter I have to declare two methods in the vehicle.h and vehicle.m file. In the vehicle.m file I don't call the object by using the self keyword but by using it's automatically created instance variable (_myProperty). Is it right?
I tried it but alway get an error and I don't know why and what is the point.
Example
Vehicle .h file:
#interface Vehicle : NSObject
#property int myProperty;
-(int) myProperty; //my new Getter method
-(void) setMyProperty: (int)updatedMyProperty; //My new Setter method
#end
vehicle .m file:
#implementation Vehicle
-(int) myProperty {
if (! _myProperty) {
_myProperty = NO;
}
return _myProperty;
}
-(void) setMyProperty: (int)updatedMyProperty {
if (_myProperty == updatedMyProperty) return;
_myProperty = updatedMyProperty;
}
#end
I always get the error "Use of undeclared identifier" and I don't know why. If I understand right I don't have to declare the ivar or its name using #synthesize because the compiler automatically creates the ivar called _myProperty for me. I just have to use #synthesize when I want to change the ivar's name.
I'm not sure why I get stuck and what the point is. Could you explain it?
Thanks in advance!
If you implement all of the accessor methods, the compiler will no longer automatically synthesize the ivar for you. In this case, you have to explicitly do so yourself. E.g.
#synthesize myProperty = _myProperty;
This is only necessary when you have manually implemented all of the accessor methods. The reason is that the compiler is smart enough to know that if you're taking over the accessor methods, you may well not need the ivar, namely that you might be doing something radically different, e.g. computing values from some other property, setting/getting values from some different store, etc. You may want the compiler to synthesize the ivar (in which case you add the above #synthesize statement), but it's equally likely that you've implemented the accessor methods because no backing ivar is needed (in which case you'd omit the above #synthesize statement).
Anyway, staying with your simple example, you get something like:
#interface Vehicle : NSObject
#property (nonatomic) int myProperty; // if you don't write atomic accessor methods, you really should be explicit that this is nonatomic
// as an aside, even if you implement accessor methods, you don't have to declare them here
//
// -(int) myProperty; //my new Getter method
// -(void) setMyProperty: (int)updatedMyProperty; //My new Setter method
#end
And
#implementation Vehicle
// since you implemented all of the accessor properties, you have to manually synthesize the ivar
#synthesize myProperty = _myProperty;
- (int) myProperty {
// do whatever you want here; note, the following doesn't make sense
//
// if (! _myProperty) {
// _myProperty = NO;
// }
return _myProperty;
}
- (void)setMyProperty:(int)updatedMyProperty {
if (_myProperty == updatedMyProperty) return;
_myProperty = updatedMyProperty;
}
#end
Clearly, there's no point in writing these particular accessor methods in the above example, because you're not offering any new functionality, so you wouldn't. You'd just avail yourself of the auto-synthesized accessor methods.
But in those cases that you really need to write your own accessor methods, then you have to explicitly tell the compiler whether you need it to synthesize the ivar for you, too, or not.

#property vs just declaring getter and setter

Is there any difference in behaviour - either at compile time or at run time - between this code...
// MyClass.h
#interface MyClass : NSObject
#property (nonatomic) SomeType myProperty;
#end
// MyClass.m
#implementation MyClass
#end
... and this code?
// MyClass.h
#interface MyClass : NSObject
-(SomeType)myProperty;
-(void)setMyProperty:(SomeType)myProperty;
#end
// MyClass.m
#implementation MyClass {
SomeType _myProperty;
}
-(SomeType)myProperty {
return _myProperty;
}
-(void)setMyProperty:(SomeType)myProperty {
_myProperty = myProperty;
}
#end
Obviously, the former version is more succinct and readable, but is there any difference in behavior? Do the synthesized getter and setter do anything more sophisticated than my straightforward implementation here? Is the declaration of a property distinguishable by introspection functions from declaration of a getter and setter? Are there any other differences I haven't thought of?
Short answer: No difference. However, some property attributes (copy or atomic) may require different accessor methods.
Long answer: There is a group of introspection functions that allow you to access all #properties declared for given class or protocol:
class_getProperty
class_copyPropertyList
protocol_getProperty
protocol_copyPropertyList
property_getName
property_getAttributes
I don't think any of these functions is useful in production code, because this is basically an implementation detail of the class. Also, there may be a getter/setter exposed in the public interface and a private property hidden in class extension.
Oh, and there's one other difference: Xcode highlights properties and plain getters differently :)
One difference is memory management. You can configure your properties to for example copy the object being set or to use a weak variable. Your code seem to be assuming ARC is active, since you are not releasing the old object and retaining the new object.
Before ARC a typical setter would to something like
-(void)setMyProperty:(SomeType *)myProperty {
if (myProperty == _myProperty) return;
[_myProperty release];
_myProperty = myProperty;
[_myProperty retain];
}
When you say you use ARC, then there is only a small difference. But none that matters.
Your ivar is #protected.
A #property creates an ivar which is #private.
Generally speaking:
So when you subclass, it is possible for your subclass to directly access the ivar you created, but not the one the property created.
BUT since you put your ivar in the #implementation block, the ivar is never seen by the subclass.
Without ARC however and SomeType being not an Objective-C object, there is a big difference. Then your setter/getter wouldn't have retain/release messages included.

Can the ivar variable created automatically by properties accessible by the child class? [duplicate]

Since recent runtimes in iOS, we are able to define properties that will generate accessors for instance variables. From what I understand, it is not mandatory to declare the instance variable used since it will be automatically done for us.
For example, if I write:
#interface MyFirstClass
#property (readonly, nonatomic) int size;
#end
and in the .m
#implementation MyFirstClass
#synthesize size;
#end
Then an instance variable named "size" will be added for me and a method called "-(int)size" will be implemented.
The problem is that when I create a second class MySecondClass which is a subclass of MyFirstClass, it seems that I can't access the instance variable size within this subclass:
#interface MySecondClass : MyFirstClass
#end
#implementation MySecondClass
- (id)init {
if (self = [super init]) {
size = 10; // this yields and error
}
return self;
}
#end
Are the automatically created instance variables private? Is there a possibility to set them as protected so I can access them in subclasses?
I know there is the possibility to declare the instance variable myself, but I'm just wondering...
With a superclass like this it works: (Is it because it's expressly declared as protected?)
#interface MyFirstClass {
int size; // defined expressly and used as #protected
}
#property (readonly, nonatomic) int size;
#end
Thank you for your help!!
Nicolas.
Any instance variable not declared in the main interface is automatically private, and this cannot be overridden. If you try to use a scope modifier when defining instance variables in the implementation, you will get an error that the specification is inconsistent.
The reason for this is that there is usually only one class per implementation file, which means the compiler doesn't know about the instance variable when compiling other classes. If you have multiple classes in the same file, the compiler could know about it, but you still aren't allowed to override the scope. Possible reasons in this case could be for consistency, or just so the compiler doesn't have to look in so many places for instance variables.
Use:
self.size = 10;
That will map to setSize method.

Defining a property in iOS class extension

I would like to add a property to UITableView in a Class Extension:
#interface UITableViewController ()
#property NSString *entityString;
#end
Then I import the extension and then I use entityString property in a subclass of UITableViewController:
#implementation CustomerTableViewController
- (void)viewDidLoad {
self.entityString = #"Customer";
...
[super viewDidLoad];
}
...
Apple documentation says:
the compiler will automatically synthesize the relevant accessor
methods (...) inside the primary class
implementation.
But when I try to execute it I get this error:
-[CustomerTableViewController setEntityString:]: unrecognized selector sent to instance 0x737b670
What am I doing wrong? maybe the property cannot be accessed by subclasses?
Try using a category with Associative References instead. It is much cleaner and will work on all instances of UIButton.
UIButton+Property.h
#import <Foundation/Foundation.h>
#interface UIButton(Property)
#property (nonatomic, retain) NSObject *property;
#end
UIButton+Property.m
#import "UIButton+Property.h"
#import <objc/runtime.h>
#implementation UIButton(Property)
static char UIB_PROPERTY_KEY;
#dynamic property;
-(void)setProperty:(NSObject *)property
{
objc_setAssociatedObject(self, &UIB_PROPERTY_KEY, property, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
-(NSObject*)property
{
return (NSObject*)objc_getAssociatedObject(self, &UIB_PROPERTY_KEY);
}
#end
//Example usage
#import "UIButton+Property.h"
UIButton *button1 = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button1.property = #"HELLO";
NSLog(#"Property %#", button1.property);
button1.property = nil;
NSLog(#"Property %#", button1.property);
A class extension is used to declare additional interface -- methods and properties -- whose implementation contract will be met within the class's primary #implementation.
Which is exactly why you can't add storage -- add ivars -- via a class extension. A class extension is an interface, no more, no less. #synthesize is what creates storage for #property declarations, but #synthesize of an #property can only appear in the #implementation of the class (whether explicitly or as a default behavior of the compiler).
Since you can't recompile the framework class, you can't add ivars to it.
#prashat's answer is one way to add storage to an existing class. However, going that route is generally undesirable; hanging state off of framework classes willy-nilly is a sign of poor design and will make your application significantly more difficult to maintain over time.
Far better to revisit your design, understand why you currently require attaching state to an object that can't directly contain it, and refactoring that requirement away.
The docs state:
Class extensions are like anonymous categories, except that the methods they declare must be implemented in the main #implementation block for the corresponding class.
When you use #property, it is roughly equivalent to declaring accessor methods. So this means you can only do such a thing if you are also the author of the "main" #implementation block of the class, which with UITableViewController, you are not.
Your only option here is Categories, which cannot add instance variables.
The docs link, and note the very last line of that page:
The implementation of the setValue: method must appear within the main #implementation block for the class (you cannot implement it in a category). If this is not the case, the compiler emits a warning that it cannot find a method definition for setValue:.

Difference between #interface declaration and #property declaration

I'm new to C, new to objective C. For an iPhone subclass, Im declaring variables I want to be visible to all methods in a class into the #interface class definition eg
#interface myclass : UIImageView {
int aVar;
}
and then I declare it again as
#property int aVar;
And then later I
#synthesize aVar;
Can you help me understand the purpose of three steps? Am I doing something unnecessary?
Thanks.
Here, you're declaring an instance variable named aVar:
#interface myclass : UIImageView {
int aVar;
}
You can now use this variable within your class:
aVar = 42;
NSLog(#"The Answer is %i.", aVar);
However, instance variables are private in Objective-C. What if you need other classes to be able to access and/or change aVar? Since methods are public in Objective-C, the answer is to write an accessor (getter) method that returns aVar and a mutator (setter) method that sets aVar:
// In header (.h) file
- (int)aVar;
- (void)setAVar:(int)newAVar;
// In implementation (.m) file
- (int)aVar {
return aVar;
}
- (void)setAVar:(int)newAVar {
if (aVar != newAVar) {
aVar = newAVar;
}
}
Now other classes can get and set aVar via:
[myclass aVar];
[myclass setAVar:24];
Writing these accessor and mutator methods can get quite tedious, so in Objective-C 2.0, Apple simplified it for us. We can now write:
// In header (.h) file
#property (nonatomic, assign) int aVar;
// In implementation (.m) file
#synthesize aVar;
...and the accessor/mutator methods will be automatically generated for us.
To sum up:
int aVar; declares an instance variable aVar
#property (nonatomic, assign) int aVar; declares the accessor and mutator methods for aVar
#synthesize aVar; implements the accessor and mutator methods for aVar
This declares an instance variable in your object:
#interface myclass : UIImageView {
int aVar;
}
Instance variables are private implementation details of your class.
If you want other objects to be able to read or set the value of the instance variable (ivar), you can declare it as a property:
#property int aVar;
This means that the compiler expects to see setter and getter accessor methods for the property.
When you use the #synthesize keyword, you are asking the compiler to automatically generate setter and getter accessor methods for you.
So, in this case the compiler will generate code similar to this when it encounters the #synthesize keyword:
- (int) aVar
{
return aVar;
}
- (void)setAVar:(int)someInt
{
aVar = someInt;
}
By default on the iPhone (and on the 32-bit runtime on the Mac), #synthesize requires an instance variable to be present in order to store the property's value. This ivar is usually named the same as the property, but doesn't have to be, for instance you could do this:
#interface myclass : UIImageView {
int aVar;
}
#property int someValue;
#synthesize someValue = aVar;
Neither #synthesize nor #property are actually required, you can create your own getter and setter methods, and as long as you create them using Key-Value Coding-compliant syntax, the property will still be usable.
The requirement for an ivar to be present as well as the #property declaration is due to the fragile base class limitation of the 32-bit Objective-C runtime on both the Mac and iPhone. With the 64-bit runtime on the Mac you don't need an ivar, #synthesize generates one for you.
Note that there are numerous keywords you can use with your #property declaration to control what sort of synthesized accessor code is created, such as readonly for a getter-only accessor, copy, atomic, nonatomic and so on. More information is in the Objective-C 2.0 Programming Language documentation.
Classes can have instance variables (ivars). These are in the first section, and are only visible to code in that class, not any outside code. I like to prefix them with an underscore to show their internal-ness. In low level terms, the ivars are added as an additional member to the struct that the class you are creating uses internally.
The second declaration, #property, is a declared property. It is not required (except when you are using #synthesize), but it helps other programmers (and the compiler!) know that you are dealing with a property, and not just two methods -setAVar and -aVar, which is the alternative way of doing this.
Thirdly, the #synthesize actually creates the methods to set and access the property from outside the class. You can replace this with your own setter and getter methods, but only do that if you need to, as the built-in ones have some features that you would otherwise have to code yourself. In fact, using the #synthesize aVar = _someVariable; syntax, you can have your property actually reference a differently named instance variable!
Short version:
The #property is just a hint to the compiler and other programmers that you are making a property and not just getter/setter methods. The instance variables are internal to the class, and otherwise cannot be normally accessed from outside it. The #synthesize just creates simple getters and setters for you, to go with your #property, but you can also just code those getters and setters yourself, like any other method.
Class A
#interface myclass : UIImageView {
int aVar;
}
If you declare like this then you can only use this variable within your class A.
But suppose in Class B
A *object=[A new];
object.aVar---->not available
For this you should **declare aVar as a property in Class A**
so class A should look like
Class A
#interface myclass : UIImageView {
int aVar;
}
#property int iVar;
and
.m file
#synthesize iVar;
So now you can use this iVar in another class Suppose B
Class B
#import "Class A.h"
enter code here
A *object=[A new];
object.aVar---->available
means
object.aVar=10;
#interface declares the instances variables of a class in obj-c. You need it to create an instance variable. However the variable is not visible outside the class by default (as the field is by default protected).
#property tells the compiler to specify a particular property accessor (get/set) method. However, you will need to use #synthesize to actually have the compiler generate the simple accessors automatically, otherwise you are expected to create them on your own.
I recently started learning iphone apps. As per my knowledge #property is used in .h file as a setter method and #synthesize in .m file as getter method. In Java we use setter and getter methods, same as Java, in Objective C we use #property and #synthesize.
Please forgive me If u think I mislead you.