Passing a class instance as a parameter to one of its own functions - objective-c

When a class of properties (let's call it class_X) is being instantiated from another class, all of class_X's methods and functions are also included in every instance.
Q1: Wouldn't that add substantial overheads, especially if there are multiple instances of that class?
The class instance (class_X) could then be passed to other methods and functions in other classes as a parameter.
Q2: Is it safe to pass it as a parameter to a C-style function (let's call it function_C) which resides in the same class (function_C resides in class_X)?
Thanks in advance.
UPDATE: Here's some code to illustrate:
class_X header:
//class_X.h
#interface class_X : NSObject
#property (nonatomic, assign) NSInteger intProp;
#property (nonatomic, strong) NSArray *arrProp;
void function_C (class_X *cx);
#end
class_X implementation:
//class_X.m
#import "class_X.h"
#implementation class_X
void function_C (class_X *cx)
{
//code...
}
#end
instantiating class_X:
#implementation someOtherViewController
- (void) viewDidLoad {
[super viewDidLoad];
class_X *cx = [[class_X alloc] init];
cx.intProp = 123;
cx.arrProp = #[#"one", #"two", #"three"];
function_C (cx); //does this not cause some sort of recursion?
}
#end

To have some naming conventions: "class instances" is akin of ambiguous. There are
instances (or instance objects) having a class.
classes, akin of type for an instance object.
class objects
So I assume that you want to use "instance objects of class X", when you write "class instances".
To your Q:
No, there is no overhead. Objective-C is a class-based programming language in contrast to JS that is prototype-based. That has the consequence that every instance has all instance methods that are declared as instance methods by the class. Therefore they are stored only a single time for all instances. The memory footprint for the methods does not depend on the number of instances are created. It is a one-timer. (The memory footprint for properties depends heavily on the number of instances.)
It is completely safe to pass references to instances to a function. Moreover the function can be defined everywhere. Of course, it has to see the interface of the class f the passed instance, probably via an import.

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.

Working between classes Objective C

I have a basic question about working with classes in objective-c and maybe just programming in general. I would like to use a variable declared in my class Signup.h in another class, Exittext.m. When I include "Signup.h" in my .m file and try to use the variable, it doesn't know what it is. Is this because they are private? Is there a way to do this or can I only use variables declared in that particular class?
#interface SignupView : UIViewController
NSMutableArray *textfields;
}
#implementation Exittextfields
- (BOOL) textFieldShouldReturn:(UITextField *)textField
{
[textfields resignFirstResponder];
return YES;
}
In traditional OO programming, accessing a variable in another class involves manually writing getter and accessor methods to expose/modify a "private" variable. In Objective-C, properties (instance variables declared with #property) takes care of generating those getters and setters automatically.
Check out this great tutorial by Ray Wenderlich.
So in your case, you'll need to declare the mutable array you want to be accessed by other classes in the .h file as a property.
Example:
#property (nonatomic, strong) NSMutableArray *myArray;
Now when a new instance of Signup is called, the array myArray can be properly accessed using either a traditional getter method or dot syntax.
Example:
Signup *sign = [[Signup alloc] init];
[sign myArray];
//OR
sign.myArray;

mutableCopyWithZone confusing requirement?

Clarification: the question is not about mutable vs immutable but about a call to super creating an instance of the correct class. I hadn't thought of using [[self class] alloc] in the base class, and this seems to solve my issues. I'll accept that anser in the next few hours if nothing better comes up :)
The Apple spec says:
If a subclass inherits NSMutableCopying from its superclass and declares
additional instance variables, the subclass has to override mutableCopyWithZone:
to properly handle its own instance variables, invoking the superclass’s
implementation first.
That's very confusing. Consider
#interface Base : NSObject<NSMutableCopying>
#property (nonatomic, assign) NSInteger value ;
#end
#implementation Base
...
#end
#interface Derived : Base<NSMutableCopying>
#property (nonatomic, assign) NSInteger value2 ;
#end
#implementation Derived
- (id) mutableCopyWithZone: (NSZone *) zone {
// Huh ???
Derived * derived = [super mutableCopyWithZone: zone] ;
...
// Huh ??????
derived.value2 = self.value2 ;
return derived ;
}
...
#end
I just do not understand how this code could possibly be correct if I follow the spec.
When the call to [super mutableCopyWithZone: zone] returns, I am expecting that the base class has only allocated enough room for its own ivars. There's no way it can tell that Derived instances need more room for its own ivars.
What is it that the documentation means, really? How should I implement this?
super only changes the way of dispatching (static instead of dynamic). But it does not change the receiver, esp. it does no upcast. In -mutableCopyWithZone: (super) self still points to an instance object of the derived class.
Trouble is possible, if the super method (or super super method and so on) does not implement the object creation in a proper way:
copy = [[BaseClass alloc] init]; // Wrong, an instance of the base class is created
copy = [[[self class] alloc] init]; // Correct, an instance of [self class] == DerivedClass is created
Using the second approach you get an instance of the derived class with full memory for its ivars.
Conclusion: Implement it in this way, if BaseClass implements its -mutableCopyWithZone: properly. Otherwise you have no other change then creating your own copy and init it.
In my books I always write, that there are little reason to use the class name inside a class. Using [self class] (in an instance method) and self (in a class method) are in 99 % the better approaches.

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