What is the difference between declaring a member in the extended interface versus in the implementation? - objective-c

I am seeing two very different behaviors for something that I thought were the exact same.
Defining my private member in the class extension like this:
#interface ClassA ()
#property ClassB* b;
#end
#implementation ClassA
-(ClassA*)initWithClassB:(ClassB*)newB
{
self.b = newB;
return self;
}
-(ClassB*)getB
{
return self.b;
}
Or defining my private member in the class implementation like this:
#interface ClassA ()
#end
#implementation ClassA
ClassB* b;
-(ClassA*)initWithClassB:(ClassB*)newB
{
b = newB;
return self;
}
-(ClassB*)getB
{
return b;
}
The way I am using this code is to create a ClassB object, initialize a ClassA object with that ClassB object, and then add the ClassA object to a mutable array
-(void)init
{
self.classAList = [[NSMutableArray alloc] init];
[self.classAList addObject:[[ClassA alloc] initWithClassB:[self createClassB1]]];
[self.classAList addObject:[[ClassA alloc] initWithClassB:[self createClassB2]]];
[self.classAList addObject:[[ClassA alloc] initWithClassB:[self createClassB3]]];
}
-(ClassB)createClassB1
{
ClassB* classB = new ClassB();
//do some init
return classB;
}
// Same thing fore createClassB2 and createClassB3 except with different data
When I use the first approach, and define my member in the interface extension, I see that each element in my mutable array is indeed what I would expect.
However, using the second approach, I see that my ClassB* b pointer in the ClassA object always ends up pointing to the most recently created ClassB object. That is, once the -(void)init method finishes, the ClassB pointers in each of the ClassA objects points to the ClassB object I created in createClassB3
What is happening here?
I should also mention that the ClassB object is a C++ object and this is a an objective-c++ class.

In your second snippet, b is just a global variable at file scope. The fact that it's inside of the #implementation ... #end is irrelevant. It is not an instance variable nor a property.

With the second approach you're creating a global variable, meaning it's not related to any instance of ClassA, so you will always have one and the same instance of *b pointing to the same object in memory. So anytime you change the value of the *b you're changing the object in memory at which the b variable is pointing, but never creating a new one; to understand it better you're basically initialising every ClassA object with the same ClassB variable (which is *b), so if you change the value at the portion of memory to which *b is pointing you're changing it for all the instances of ClassA created.
Hope it's clear enough.

Related

Variable losing value in delegation pattern

I'm trying to learn about delegation in Objective-C, and am having a minor issue with a variable losing it's data in the transfer process. I have Class1 that contains an NSMutableArray. The array gets populated, then I would like to transfer the array's values to Class2, and display it. Here is the relevant code in Class1:
//Class1.h
#class Class1;
// define the protocol for the delegate
#protocol Class1Delegate
#required
-(void)sayHello:(Class1 *)customClass withAntArray:(NSMutableArray *)antArray;
#end
#interface Class1 : MySuperClassName
#property (nonatomic, assign) id delegate;
-(void)helloDelegate;
#end
//Class1.m:
#interface Class1 ()
#property (nonatomic, strong) NSMutableArray *antOccurenceTimes;
#end
#implementation Class1
#synthesize antOccurenceTimes;
-(void)helloDelegate
{
// send the message to the delegate
[_delegate sayHello:self withAntArray:self.antOccurenceTimes];
}
Now, this is what I have in Class2:
#import "Class1.h"
#interface Class2 : UIView <Class1Delegate>
#end
// Class2.m:
- (void)appropriateTimeToCallMethod {
Class1 *initAntMarks = [[Class1 alloc] init];
initAntMarks.delegate = self;
[initAntMarks helloDelegate];
}
-(void)sayHello:(Class1 *)customClass withAntArray:(NSMutableArray *)antArray {
NSLog(#"Hello! %#", antArray.description);
}
The antArray.description reads as "NULL". Now, I figured that obviously it will be null, because I just created an entirely new instance of the class right before calling upon the needed method. I feel like I may have something mixed up, and being so new to delegation, I'm not sure exactly what. Does anyone know what I need to tweak to utilize Delegation?
I forgot to add that I did initialize it in Class1, and it gets populated just fine. It's only in class2 that this is occurring.
I initalize antOccuranceTimes in a separate method in ClassA in the snippet below, and the NSLog fires twice...
NSLog(#"Array initalized in class A");
antOccurenceTimes = [NSMutableArray new];
Change this line:
#property (nonatomic, assign) id delegate;
to:
#property (nonatomic, weak) id <Class1Delegate> delegate;
assign should only be used for C primitives, not Objective-c object references. You should also be checking if your object actually conforms to the delegate before messaging the delegate.
Edit:
I think you may be confused about the purpose of delegation.
Class1 *initAntMarks = [[Class1 alloc] init];
initAntMarks.delegate = self;
[initAntMarks helloDelegate];
Why are you calling a method on an object which in turn calls a delegate method when you could simply create a method that returns the NSMutableArray? The way you have your code currently set up requires that before the call to -helloDelegate you have to have filled the array with the appropriate objects. The purpose of delegation in MVC is to inform an object about an event that took place inside of another object. You are "delegating" the task off to another object, or you could say, that another object if responsible for the fulfillment of the task. Read the Apple Docs on Delegation. Delegation in your code is not the correct pattern to implement, as I stated you can simply return that array with a method call.
Edit 2:
There are two ways you can achieve this, through property methods or through an explicit method that returns your array. If you choose to use property methods, the property declaration must be in the public interface i.e. the .h file so that your class can all the accessors when the object is being implemented.
//Inside the .h
#property (nonatomic, strong) NSMutableArray *antOccurenceTimes;
This will automatically provide you with two accessor methods for the antOccurenceTimes property. These are the getter -antOccurenceTimes and setter -setAntOccurenceTimes: methods. Now after you initialize the class and fill your array you can call -antOccurenceTimes to return the array.
You can also create an explicit method that return the array:
- (NSMutableArray *)hello{
//Do something here
return _antOccurenceTimes;
}
You have not yet initialized the antOccurenceTimes. Of cause it is nil. There are many options depending on what you need. You can, for example, initialize it in a init function:
- (instancetype)init {
self = [super init];
if( self ) {
antOccurenceTimes = [NSMutableArray array];
[antOccurenceTimes addObject:#"Hello World"];
}
}
Or maybe initialize it before you call the delegate the function.
-(void)helloDelegate
{
// send the message to the delegate
self.antOccurenceTimes = [NSMutableArray array];
[self.antOccurenceTimes addObject:#"Hello World"];
[_delegate sayHello:self withAntArray:self.antOccurenceTimes];
}
I think you get my point.

storing instance reference in singleton in obj-c

Let's say I have 2 classes, A and B. A is a singleton. I declare A in B, so I can access the singletons vars in methods in B.
B then creates an instance of another class, say class C.
C Then creates an instance of another class, say class D.
What I need to do is run a method in the instance of class B, from class D, and that's what is driving me nuts.
My first thought was to put a reference to the instance of class b, in my singleton (class A), something like...
sharedInstance.classBReference = self;
..and then declare the singleton in Class D, and then use something like this in class D instance...
[sharedInstance.classBInstance classBInstanceMethod];
But of course as soon as I did..
classB *classBReference;
In the header of my singleton, it game me the "unknown type" which I read about on here, so instead, I put a
#class classB;
above the #interface, and then I was able to declare...
classB *classBReference;
Without an error of unknown type, but in the init method of class B, this...
sharedInstance.classBReference = self;
Still gives me an error of type
"property classBReference not found on objet of type "class A*" (the singleton) did you mean to access ivar classBReference?"
And I have no idea why it's doing that, what's the solution? or is there a better way to do what I'm trying to do?
Dots and Arrows
The "dot notation" is a somewhat recent addition to Objective-C and provides a shorthand notation for accessors. If you have a pointer to an object (or a struct!), you cannot access its instance variables with . but only with ->.
Your line
sharedInstance.classBReference = self;
is exactly the same as
[sharedInstance setClassBReference:self];
The problem is that you don't have any such method -setClassBReference:. In order to set the instance variable, you must instead write
sharedInstance->classBReference = self;
#protected variables
After switching your line with this one, you may (if you haven't made it #public) see the error
Instance variable 'classBReference' is private
In this case, you need to alter your classA interface so that classBReference is declared to be #public. Your list of instance variables in classA should look something like
#interface classA : NSObject
{
//#protected
//(The #protected keyword is optional when at the beginning of the list; instance
//variables are protected by default, which is why you're needing to declare your
//instance variable classBReference to be #public (since classB is not a subclass
//of classA and consequently cannot access its protected instance variables).
//....
//some protected instance variables
//....
#private
//....
//some private instance variables
//....
#public
//....
//some public instance variables
classB *classBReference;
//....
#protected
//....
//some more protected instance variables
//Note that #protected is not optional in order to make the instance variables
//here be protected since they are declared subsequent to the prior #public.
//....
}
//....
#end
Using #properties
The case of classBReference
That being said, it is widely regarded as a better practice to use accessors rather than instance variables in general. In order to do this, you should add a property to your classA interface:
#interface classA : NSObject
{
classB *classBReference;
}
#property classB *classBReference;
#end
and synthesize the classBReference property to access the classBReference instance variable in classA's implementation as follows:
#implementation classB
#synthesize classBReference = classBReference;
The general set-up
The #synthesize is somewhat unclear on account of the fact that we have both an instance variable and a property with the same name. Some clarification is in order. In general, in a class's ("MyObject" in this example) #interface one declares an instance variable ("myVariable" in this example) and a property ("myProperty" in this example).
#interface MyObject : NSObject
{
SomeObject *myVariable;
}
#property SomeObject *myProperty;
#end
In the class's #implementation one has the line
#synthesize myProperty = myVariable.
The result of this code is that, given an instance
MyObject *object = //...
of the class, one is able to write
SomeObject *someObject = //...
[object setMyProperty:someObject];
and
SomeObject *someOtherObject = [object myProperty];
The result of calling -setMyProperty: on the instance of MyObject is that myVariable is set equal to the argument passed into the method--in this case someObject. Similarly, the result of calling -myProperty on the instance of MyObject is that myVariable is returned.
What does it get us?
Without the #property and #synthesize directives, one would have to declare the methods
- (void)setMyProperty:(SomeObject *)myProperty;
- (SomeObject *)myProperty;
manually and define them manually as well:
- (void)setMyProperty:(SomeObject *)myProperty
{
myVariable = myProperty;
}
- (SomeObject *)myProperty
{
return myVariable;
}
The #property and #synthesize provide some abridgment to this code. The amount of code that is generated for you becomes even more beneficial when you use various of the property attributes.
Note: There is more to say about the #property and #synthesize directives. For a start, not only can you write #synthesize myProperty; omitting the variable name, you can omit the synthesizing of myProperty entirely, and the variable names that are used automatically are different from one another in these two cases.
A Bit More on Dot Notation
The dot notation from your question provides another layer of abbreviation. Rather than having to write
[object setMyProperty:someObject];
you are now able to write
object.myProperty = someObject;
Similarly, rather than having to write
SomeObject *someOtherObject = [object myProperty];
you are now able to write
SomeObject *someOtherObject = object.myProperty;
It is important to note that this is just just notation. Though it "kinda looks like" we're doing simple assignment when we "set object.myProperty equal to someObject", that is not the case. In particular, when we execute the line
object.myProperty = someObject;
the method
- (void)setMyProperty:(SomeObject *)someObject
is executed. For this reason, dot notation is a subject of some contention. It is a convenience, but it is important to keep in mind what your code is doing.
The error message tells you the answer. You should define classBReference as property or use classBReference as ivar.
It sounds like you'd be less confused by avoiding the global variable (aka singleton). Give the C a reference to the B when the B creates the C. Give the D a reference to the B when the C creates the D.
If you need to avoid a retain cycle, make the back-references to the B either weak (if your deployment target is at least iOS 5.0) or unsafe_unretained (if your deployment target is earlier than iOS 5.0).

Objective-C: What is the difference between + and - in getters and setters?

What is the difference of using:
+ (id) myMethod;
// Rather than
- (id) myMethod;
Using a + declares the method as a class method, or a method that can be called directly on the class, where the class is the object. So when you have this:
#implementation Foo
+(NSString*)method1 {
return #"Foo";
}
-(NSString*)method2 {
return #"Foo";
}
#end
The methods are called in different ways:
[Foo method1]; //=> #"Foo"
Foo* f=[[Foo alloc] init];
[f method2]; //=> #"Foo"
One other thing to note is that class methods don't have access to an instance, which means they can't access any kind of instance variables.
#Linuxios pretty much summed up the concept of class and instance method. However, since you mentioned getters and setters in your title, I want to point out that in Objective-C you can use properties instead of writing your own accessor methods. For example,
In the header file, you will have something like this:
#interface MyObject : NSObject
#property (nonatomic,retain) NSSet* mySet;
#end
In the m file, you wil have something like this:
#implement MyObject
#synthesize mySet;
#end
To access the set in another class you can do it like this:
myObject.mySet; // assuming myObject is an instance of the MyObject class
The top one is a class method (no instance required)
The second one is a instance variable (attached to a specific instance).
This answer explains the methods quite well:
Method Syntax in Objective C
[MyObject myMethod]; // did not have to create an instance
MyObject* myNewObject = [[MyObject alloc] init] autorelease];
[myNewObject myMethod]; // had to create an instance

About moving few methods to the superclass

I need to move the same method from 4 different classes to the superclass.
Such methods are exactly the same except for the type of a variable declared in them:
For example, in the method in the first class I have
FirstClass var = [[FirstClass alloc] init]
in the second class
SecondClass var = [[SecondClass alloc] init]
and so on.
What's the best way to implement this variation in the superclass ?
Should I use NSClassFromString in the superclass and get each string from each method in the subclasses?
thanks
I'm not 100% sure I get what you mean. So I could be answering the wrong question
If inside your class you need to use an object (I've called it worker below) to do your work, but the class of this object is not known til later, you can use dependency injection (DI).
MyClass.h
#interface MyClass : NSObject
#property (nonatomic, retain) id<WorkerInterface> worker;
#end
MyClass.m
#implementation MyClass
#synthesize worker = _worker;
- (void)myMethod;
{
[self.worker doSomething];
}
// You could also provide a default class to use if one is not passed in
//
// - (id<WorkerInterface)worker;
// {
// if (!_worker) {
// _worker = [[DefaultWorker alloc] init];
// }
// return _worker;
// }
#end
Now whenever I instantiate this class I can simply pass in the appropriate object to be used e.g:
MyWorkerClass *worker = [[MyWorkerClass alloc] init]; // <- Conforms to #protocol(WorkerInterface)
MyClass *instance = [[MyClass alloc] init];
instance.worker = worker;
[instance doSomething];
If all the different types of iVar's you intend on initializing in the subclasses are descended from a common class, then I'd store that class in the super, or else just store it as an id. Then, setup a property accessor in each of your subclasses the casts the iVar as you need it.
#interface superClass : NSObject{
id _superIvar;
}
#end
#implementation superClass : NSObject
....super's code....
#end
Now in the implementation of the subclass declare a property in a category, shown below (or in the interface, if you want it public)
#interface subClass (private)
#property (strong) ClassType *superIvar;
#end;
#implementation
- (void) setSuperIvar:(ClassType *)superIvar{
_superIvar = superIvar;
}
- (ClassType *) superIvar{
return (ClassType *) _superIvar;
}
- (void) someMethodThatUsesSuperIvar{
[self.superIvar doSomething];
}
#end
Alternatively, if you don't want to open your _superIvar to direct access, you can set a property on the superclass and access through the property on the subclass. But in this way you can easily access super's ivars cast to the appropriate type.

Messaging between two classes

I have a basic question about fetching values through different classes.
I have a classA which fills an array (If i print it out it is not empty).
LATER in class B i want to load this Array: I call a function from class A which returns the Array of class A. But in class B if i call my new array then is it null.
I am a bit confused, because i think i retain every value of the array, but its still null. I tried also a lot of different possibilities. I think its a basic OOP syntax fault i produce?!
//CLASS_A.h
#interface classA {
NSMutableArray* buoyArray;
}
#property (nonatomic, retain) NSMutableArray * buoyArray;
-(NSMutableArray*)getArray:(NSMutableArray*)_array;
//CLASS_A.m
...
-(NSMutableArray*)getArray:(NSMutableArray*)_array {
_array=buoyArray;
return _array;
}
//CLASS_B.h
#import "CLASS_A.h"
#class classA;
#interface classB ...
classA *mapSource;
NSMutableArray * buoyArray;
}
#property(nonatomic,retain) classA *mapSource;
//CLASS_B.m
buoyArray=[mapSource getArray:buoyArray];
NSLog(#"%#",buoyArray);
Actually you you are making new object of class A by calling alloc so by init it reintialize all properties values for that instance.
What you need,if you are pushing class B over class A then, fetch existing class A object from stack, by using this line.
mapSource = (ClassA *)[self.navigationController.viewControllers objectAtIndex: [self.navigationController.viewControllers count]-2];
then call this
buoyArray=[mapSource getArray:buoyArray];
NSLog(#"%#",buoyArray);