Defining a property in iOS class extension - objective-c

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:.

Related

Instantiating multiple objects of the same class in Interface Builder results in shared property

I am trying to use NSPopUpButtons in my OSX program. In order to use KVO for its string and its index, I wrote a custom class (DLPopUpButtonManager).
#interface DLPopUpButtonManager : NSObject
#property NSArray *contentArray;
#property NSString *selectionString;
#property NSNumber *selectionIndex;
#end
That class works fine, when used only once in the program. But…
When I use more than one instance their contentArray is shared, meaning the two contentArrays point to the same instance. Huh?? That totally confuses me.
(Encapsulation, etc.)
I have two NSPopUpButtons that each are connected to an objects of class DLPopUpButtonManager. Those two classes are instantiated in Interface Builder though two objects. And in my AppDelegate I initialize them.
#interface AppDelegate : NSObject <NSApplicationDelegate>
#property (weak) IBOutlet DLPopUpButtonManager *pUBM_1;
#property (weak) IBOutlet DLPopUpButtonManager *pUBM_2;
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[self.pUBM_1 setContentArray:[NSArray arrayWithObjects:#"Female", #"Male", nil]];
[self.pUBM_2 setContentArray:[NSArray arrayWithObjects:#"Tall", #"Short", nil]];
[self showDetails:nil];
}
I find that both instances (confusingly and unwanted) use the same contentArray.
I investigated using breakpoints and saw that I have indeed two separate instances of DLPopUpButtonManager, but their contentArrays have the same pointer value.
Printing description of $20: <DLPopUpButtonManager: 0x6080000100b0>
Printing description of $23: <DLPopUpButtonManager: 0x6080000100c0>
Printing description of $25: <__NSArrayI 0x600000223ba0>
(
Tall,
Short
)
Printing description of $24: <__NSArrayI 0x600000223ba0>
(
Tall,
Short
)
(lldb)
I can’t find anything like that through Google or here on SO. Who can tell me, what I am doing wrong here?
I uploaded a little sample program to GitHub (https://github.com/donnerluetjen/PopUpButtonEtude).
Thanks for any input on that issue.
Try moving the underlying ivars for your your array and selection index properties into a private extension in the .m file, to ensure that they are not in fact static variables.
#interface DLPopUpButtonManager (){
NSArray *_contentArray;
NSUInteger _selectionIndex;
}
Thanks to tjboneman I could solve my problem, and I read some more about instance variables and static instance variables. Here is what I found after some serious searching:
From Apple's docs, The Objective-C Language | Defining a Class:
Class Interface
...
Note: Historically, the interface required declarations of a class’s instance variables, the data structures that are part of each instance of the class. These were declared in braces after the #interface declaration and before method declarations:
#interface ClassName : ItsSuperclass
{
// Instance variable declarations.
}
// Method and property declarations.
#end
Instance variables represent an implementation detail, and should typically not be accessed outside of the class itself. Moreover, you can declare them in the implementation block or synthesize them using declared properties. Typically you should not, therefore, declare instance variables in the public interface and so you should omit the braces.
...
Class Implementation
The definition of a class is structured very much like its declaration. It begins with an #implementation directive and ends with the #end directive. In addition, the class may declare instance variables in braces after the #implementation directive:
#implementation ClassName
{
// Instance variable declarations.
}
// Method definitions.
#end
Thanks again, tjboneman for pointing me in the right direction.

Objective-C instance variables?

I'm sure my confusion here is just a result of being stuck in a "Java mindset" and not understanding how Obj-C differs in this case.
In Java, I can declare a variable in a class, like this, and each instance of that class will have it's own:
MyClass {
String myVar;
MyClass() {
// constructor
}
}
In Obj-C I tried to do the same thing by declaring a variable only in the .m file like this:
#import "MyClass.h"
#implementation MyClass
NSString *testVar;
#end
My expectation here was that this variable has a scope limited to this class. So I created a second class (identical):
#import "MySecondClass.h"
#implementation MySecondClass
NSString *testVar;
#end
What I'm seeing (and has me baffled) is that changing the variable in one class, affects the value seen in the other class. In fact, if I set a breakpoint, and then "Jump to Definition" of the variable, it takes me to th
I've created an extremely small Xcode project that demonstrates the problem here.
Change this:
#implementation MyClass
NSString *testVar;
#end
to:
#implementation MyClass {
NSString *testVar;
}
// methods go here
#end
and you'll get what you expected.
As you had it, you are actually creating a global variable. The two global variables were combined into one by the linker which is why both changed when you set one. The variable in curly braces will be a proper (and private) instance variable.
Edit: After being downvoted for no apparent reason, I thought I'd point out the "old" way of doing things, and the new way.
The old way:
SomeClass.h
#interface SomeClass : UIViewController <UITextFieldDelegate> {
UITextField *_textField;
BOOL _someBool;
}
#property (nonatomic, assign) BOOL someBool;
// a few method declarations
#end
SomeClass.m
#implementation SomeClass
#synthesize someBool = _someBool;
// the method implementations
#end
Now the new and improved way with the modern Objective-C compiler:
SomeClass.h
#interface SomeClass : UIViewController
#property (nonatomic, assign) BOOL someBool;
// a few method declarations
#end
SomeClass.m
#interface SomeClass () <UITextFieldDelegate>
#end
#implementation SomeClass {
UITextField *_textField;
}
// the method implementations
#end
The new way has several advantages. The primary advantage is that none of the implementation specific details about the class appear in the .h file. A client has no need to know what delegates the implementation needs. The client has no need to know what ivars I use. Now, if the implementation needs a new ivar or it needs to use a new protocol, the .h file doesn't change. This mean less code gets recompiled. It cleaner and much more efficient. It also makes for easier editing. When I'm editing the .m file and realize I need a new ivar, make the change in the same .m file I'm already editing. No need to swap back and forth.
Also note the implementation no longer needs an ivar or #synthesize for the property.
What you probably want (unless you're using a very old OS and compiler) is to just use property syntax. I.e.:
#interface MyClass : NSObject
// method declarations here ...
#property (copy) NSString* myVar;
// ... or here.
#end
This will do what you intended to do. This will implicitly synthesize an instance variable and a getter/setter pair for this variable. If you manually wanted to create the instance variable (you generally don't need that unless you need your code to work on very old MacOS versions), this is what the above code does under the hood to create the ivar:
#interface MyClass : NSObject
{
NSString* _myVar;
}
// method declarations here.
#end
Note the curly braces, which tell the compiler that this is not just a global variable somewhere in between the methods, but actually an instance variable that belongs to this object.
If you are creating the property only for internal use and don't want clients of your class to mess with it, you can hide this away a little bit in everything but the oldest ObjC compilers by using a class extension which "continues" the class declaration from the header, but can be placed separate from it (so usually in your implementation file). A class extension looks like a category without a name:
#interface MyClass ()
#property (copy) NSString* myVar;
#end
And you can either put your property declaration in there, or even ivar declarations (again wrapped in curly brackets). You can even declare the same property as readonly in the class interface, and then re-declare it identical, but as readwrite in the extension, so that clients only read it, but your code can change it.
Note that, if you didn't use ARC (that is, you've switched off the default of Automatic Reference Counting), you would have to set all your properties to nil in your dealloc method (unless they're set to weak or assign of course).
NB - All the above are #interface sections. Your actual code will go in separate #implementation sections. This is so you can have header files (.h) you can hand off to your class's clients that just contain the portions you intend them to use, and hide away implementation details in the implementation file (.m) where you can change them without having to worry someone might have accidentally used them and you'll break other code.
PS - Note that NSStrings and other objects that you want the immutable flavor of, but that also exist in a mutable flavor (i.e. NSMutableString) should always be copy properties, because that will turn an NSMutableString into an NSString so that nobody on the outside can change the mutable string underneath you. For all other object types, you generally use strong (or retain if not ARC). For your class's owner (e.g. its delegate) you usually use weak (or assign if not ARC).
In Java
MyClass {
String myVar;
MyClass() {
// constructor
}
}
In Objective-c
MyClass.h
#interface MyClass : NSObject{
NSString* str; // Declaration
}
#end
MyClass.m
#implementation MyClass
-(void)initializieTheString
{
//Defination
}
#end
In objective-c, you define the variable as private by doing like so
MyClass.h
#interface MyClass : NSObject{
NSString* _myTestVar; // Declaration
}
#end
and refer to it in the implementation class by doing like so
MyClass.m
#import "MyClass.h";
#implementation MyClass
-(void)initializieTheString
{
_myTestVar= #"foo"; //Initialization
}
#end

Objective-C: Compiler error when overriding a superclass getter and trying to access ivar

I'm working on building an iOS 6 app.
I have a class TDBeam which inherits from superclass TDWeapon.
The superclass TDWeapon declares a #property in the TDWeapon.h file:
#interface TDWeapon : UIView
#property (nonatomic) int damage;
#end
I do not explicitly #synthesize the property, as I'm letting Xcode automatically do so.
In the subclass TDBeam I override the getter in the TDBeam.m file:
#import "TDBeam.h"
#implementation TDBeam
- (int)damage {
return _damage;
}
#end
Xcode auto-completes the getter method name, as expected. But when I attempt to reference the _damage instance variable (inherited from the superclass), I get a compiler error:
Use of undeclared identifier '_damage'
What am I doing wrong here? I've tried explicitly adding #synthesize, and changing the name of the _damage ivar, but the compiler doesn't "see" it or any other ivars from the superclass. I thought ivars were visible and accessible from subclasses?
Synthesized ivars are not visible to subclasses, whether they are explicitly or automatically created: What is the visibility of #synthesized instance variables? Since they are effectively declared in the implementation file, their declaration isn't included in the "translation unit" that includes the subclass.
If you really want to access that ivar directly, you'll have to explicitly declare it (in its default "protected" form) somewhere that the subclass can see it, such as a class extension of the superclass in a private header.
There are a lot of posts on this topic on Stack Overflow, none of which offer simple concrete advice, but this topic sums it up most succinctly, and Josh's answer is the best in any.
What he kinda stops short of saying outright, is, if this is the kind of thing you want to do, don't use #property at all. Declare your regular protected variable in your base class as he says, and write you're own setters and getters if you need them. The ivar will be visible to any subclasses who can then write their own setters/getters.
At least that's where i've landed on the issue, although I'd a total newb to subclassing.
The idea of creating private headers to host your anonymous category and re-#sythesizing your ivars in your subclass just seems wrong on so many levels. I'm also sure I've probably missed some fundamental point somewhere.
Edit
Okay after some lost sleep, and inspired by Stanford's 2013 iTunes U course, here I believe is an example solution to this problem.
MYFoo.h
#import <Foundation/Foundation.h>
#interface MYFoo : NSObject
// Optional, depending on your class
#property (strong, nonatomic, readonly) NSString * myProperty;
- (NSString *)makeValueForNewMyProperty; //override this in your subclass
#end
MYFoo.m
#import "MYFoo.h"
#interface MYFoo ()
#property (strong, nonatomic, readwrite) NSString * myProperty;
#end
#implementation MYFoo
// Base class getter, generic
- (NSDateComponents *)myProperty {
if (!_myProperty) {
_myProperty = [self makeValueForNewMyProperty];
}
return _myProperty;
}
// Replace this method in your subclass with your logic on how to create a new myProperty
- (NSString *)makeValueForNewMyProperty {
// If this is an abstract base class, we'd return nil and/or throw an exception
NSString * newMyProperty = [[NSString alloc]init];
// Do stuff to make the property the way you need it...
return newMyProperty;
}
#end
Then you just replace makeValueForNewMyProperty in your subclass with whatever custom logic you need. Your property is 'protected' in the base class but you have control over how it is created, which is basically what you are trying to achieve in most cases.
If your makeValueForNewMyProperty method requires access to other ivars of the base class, they will, at the very least, have to be be public readonly properties (or just naked ivars).
Not exactly 'over-ridding a getter' but it achieves the same sort of thing, with a little thought. My apologies if, in trying to make the example generic, some elegance and clarity has been lost.

Inheriting accessors in Objective-C

this is my first post; this site has been an invaluable resource.
I'm fairly new to objective-c so please bear with.
So I have a base class with a few properties which I want "private" so I made them readonly. To be clear, I don't want them mutable externally, but I DO wan't to use the 'set' accessor within this class. So...
// .h file
#interface Vehicle
#property (nonatomic, readonly) int speed;
#end
Also I repeated the property declaration within a category interface block to make the accessors writable in this class
// .m file
//Private properties and methods
#interface Vehicle()
#property (nonatomic, readwrite) int speed;
#end
#implementation
#synthesize speed = _speed;
- (void) someMethod {
[self setSpeed:10]; // Works fine
}
#end
But now if I inherit this class the derived class no longer has the set accessor method (setSpeed in my case). Do I need to synthesize again? Seems like that would defeat the purpose of inheritence. I know i can modify the instance variable directly (_speed = 10;) but would rather not. I'm sure there's something wrong with my understanding. Thanks!
// Example
#interface Ship : Vehicle
#end
#implementation
- (void) someOtherMethod {
[self setSpeed: 2]; // DOES NOT WORK, would like it to
}
#end
But now if I inherit this class the derived class no longer has the set accessor method (setSpeed in my case).
Actually, it does have the set accessor, it's just that the compiler doesn't know about it. You have a choice:
put the class extension (the #interface Vehicle() .... #end bit in a separate header file that gets imported into the .m for Vehicle and its subclasses (or use a category)
redeclare the read/write property in a class extension for the subclass. To avoid a warning, use #dynamic speed in the subclass's implementation.
Since there is no such thing as 'protected' methods, you need to create a private shared header where your anonymous category goes. Then both your original implementation and your derived classes include this header to get access to this 'private' stuff.

Objective-C releasing a property declared in a category?

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.