How can you share ivars between classes.? - iphone

In one classes .h i have
NSMutableArray *rountines;
and in another classes .m i want to do something like this
[routines addOject:#"Hello];
the other class is an ModalViewController type set up.
So, in essence i'd like the .m file of the MVC to be able to read, and edit and do other things to the ivars i declare in the header.
Cheers,
Sam
edit
Another example, which is similar to what im trying to achieve is like an edit screen.

You can't share ivars between classes really. ivar stands for instance variable, and that is a variable that belongs to some particular instance of an object. The way to solve this problem is to allow other objects to access this object's state. This is most commonly done through setter and getter methods. Objective-C 2.0 makes this easier by providing the #property and #synthesize keywords.
If you had access to the object that had the routines array, you could access it through its property (getter method) like this:
[[someObject routines] addObject:#"hello"];

you can either do this by making the ivars you want to share globals (in which case they would be ivars of the singleton class or app delegate class) or by passing a reference to the class you want to modify the ivars of as an argument to a method of the ModalViewController class:
#implementation ModalViewController
......
-(void)addObjectToRoutinesFromClass: (MyClass *)myclass {
[myclass.routines addObject:#"Hello"];
}
#implementation MyClass
......
ModalViewController *myModalViewController = [[ModalViewController alloc] init];
[myModalViewController addObjectToRoutinesFromClass:self];
#end

Related

Subclassing NSMutableArray

I've been watching CP193 classes on itunes and the common message that comes about is reusability.
I'm creating a program that has a list in the form of an NSMutableArray. I will be accessing this class over and over again.
So I created an NSMutableArray class with a function to setup NSStrings in the array
#interface Geology : NSMutableArray
- (void) setuparray;
In the implementation file I have
[super addobjects:#"object1"];
I would like to initialise this object with objects already inside. I imported the header file inside my ViewController with the following code:
Geology *geology = [[Geology alloc] initWithCapacity:5];
[geology setuparray];
NSLog(#"%#", [geology objectAtIndex:1];
However the program does not compile with the following error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSMutableArray initWithCapacity:]: method only defined for abstract class. Define - Geology initWithCapacity:]!
So from that I need to define the capacity inside my new file. However even though I add [Super initWithCapacity] inside the file it still does not work?
edit:
Geology.h
#interface Geology : NSMutableArray
- (void) setupGeology;
#end
Geology.m
#implementation Geology
- (void) setupGeology{
[super initWithCapacity:1];
[super addObject:#"object1"];
}
#end
In my ViewController I have
#import "Geology.h"
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
Geology *geology = [[Geology alloc] initWithCapacity:5];
[geology setupGeology];
NSLog(#"%#", [geology objectAtIndex:1]);
}
First of all you don't have initWithCapacity declared and defined in your .h and .m since NSMutableArray is an abstract class, so you will need to have to define this and secondly I am not sure if this is the correct way to do it... Whenever you need to add extra functionality to an existing class you can always use categories in objective-c. Subclassing is uusally done when you need to add extra properties to a class along with some functionality.
I believe you should look into categories , because subclassing NSMutableArray is a very rare thing and I have never felt the need to do it.
You can refer to this answer for more clarity.
It looks like all you want to do is to create an custom initialiser for a NSMutableArray so that it is better suited to the way you use it in your application.
You don't have to subclass NSMutableArray to do this.
If all you want to do is add functionality to an existing class and not add extra storage, you can just create a category on NSMutableArray that performs your setup for you.
You're subclassing NSArray when it's inappropriate. Subclassing is used for specialising or extending. You're not specialising or extending NSArray here - you're just using it. So just use NSArray, as normal; no need to subclass. So you might have a helper data object that contains an NSArray as a property.
Also, I'd expect a subclass of NSArray to at least have 'Array' in the class name.
Note also that when adding functionality to an existing class in Objective C, class categories are sometimes used rather than subclassing. Categories are particularly useful when you want to add new methods to an existing class without adding any new state (i.e. ivars/properties).

When do I need to have both iVar and a property?

I see some examples sometimes would declare a property as well as variable other times they do not .e.g. some time I see code like this
#interface Test : NSObject
{
UIProgressView* _progressView;
}
#property (nonatomic,retain)UIProgressView* progressView;
#end
at other times I will come across
#interface Test : NSObject
#property (nonatomic,retain)UIProgressView* progressView;
#end
Why what are the reasons ? I am learning and almost always use property and variable both.
I have used UIProgressView just as example.
Using ivars instead properties is only useful if you want #protected access (access from subclasses only), or support the old runtime (which required both).
It depends whether the property is synthesized against an iVar or derived in some other way (or against another iVar).
IF we have an instance of the class - i.e:
Test *myTest = [[Test alloc] init];
Then basically the property declaration
#property (nonatomic,retain)UIProgressView* progressView;
is telling anyone interested in using the interface that they can access the following two functions on an instance of this class:
[myTest progressBar];
[myTest setProgressBar:aProgressBar];
And objective C also lets you use shorthand notation:
myTest.progressBar =
xxx = myTest.progressBar
which does exactly the same thing.
It is not necessary for these two methods to be implemented via an iVar of the same name as the property, or even via an iVar at all (they could do even do a database fetch or derive the value).
If you #synthesize the property (which means you want the precompiler to generate the above methods for you) and don't explicitly specify an iVar on the #synthesize directive, then the methods described above will automatically be generated (due to the synthesize method) to set or get the value to/from an iVar of the same name as the property (and the implementation will include retain/release logic depending on the property directive.
If you don't #synthesize the property then you provide your own implementation and it can be anything you want. It is also possible to #synthesize the property but include a directive to use a different iVar in the method definition:
#synthesize progressBar=someOtheriVar;
in which case you will not see an iVar of the same name as the property in the header file either.

Basic objective C variable declaration

I am puzzled by how is variable declared in objective C.
1: I see #property and #synthesize statement being used. My question regarding that is, what are these 2 statement for? Why are they always used together? I guess #synthesize is a shortcut to create the getter and setter?
2:Say, I want to declare an NSMutableArray that would be only be accessible inside the class that was declared in. I have to perform myArray = [[NSMutableArray alloc] init] before using the addObject method to write something to it. When do I release the array then?
3:Is there a different way to declaring a variable that is only accessible only at the class it was declared to being accessible at all classes?
4:Similar to question 2, but now the variable is an NSString. Why I don't have to alloc & init it to share the same variable within its own class? Whats the different between self.myString = #""; to myString = #"";
Thanks a lot.
For your first question:
#property (nonatomic, retain) NSString * someProperty;
This declares a property of the class. It becomes part of the public contract of the class but still lacks something important - actual implementation
#synthesize someProperty;
This is compiler sugar, its creates a getter and setter method for your property. To wit, this is the implementation that is needed in order to actually use your property in your class and from other classes.
You will in almost all situations, always have a #synthesize for each #property you declare.
For your second question:
You are correct about how to initialize your array property. In order to release it you would do the following in your classes dealloc method:
- (void) dealloc {
self.myarray = nil;
[super dealloc];
}
This effectively releases the array (assuming you declared your property with the keyword retain).
And for your last question:
Properties of a class are always available from other classes. In order to create a globally accessible variable you would declare it as static.
Ad 1: a property is a construct to control access an ivar (usually private) by getters and setters. Actually, a property doesn't even have to have a supporting ivar. Yes, #synthesize generates getter and setter (and ivar).
Ad 2: You release it when you don't need it anymore. When that is depends on the logic of your code.
Ad 3: If I understand that correcttly, you want #private ivars. Normally, ivars are protected, i.e. only accessible inside the class or in derived classes. Private ivars are only accessible inside the class itself. Properties are publicly accessible.
Ad 4: myString = #"" writes to the ivar directly, while self.myString = #"" uses the property setter.
You need to get a text on Objective-C or find an online tutorial -- it's a sufficiently arcane language that you can't hope to pick it up in dribs and drabs.
There are variables and there are properties -- two different things that intersect somewhat.
You can declare plain old instance variables the same way as in C/C++, more or less:
NSArray* myArray;
eg, placed in the {} enclosed section of the #interface.
But you can also have a PROPERTY, which you declare by saying #property in the #interface declaration (after the closing }). A property has a getter method -- by default called myProperty -- and a putter method -- by default called setMyProperty. If myProperty is the same name as one of your instance variables then you can use #synthesize to automatically create these methods.
Note that properties may be automatically retained when the default setter method is used. This is fairly convenient in terms of managing storage.
But managing storage is a big topic, one that you MUST read some good tutorial on -- we can't explain it in a few paragraphs.
1) #property declares a publicly accessible variable and associated getter and setter. #synthesize causes the compiler to automatically generate the definition (code) of the getter and setter.
2) You would declare the NSMutableArray in your class declaration, in the header file. You would initialize the variable in your init method, and you would release the variable in your dealloc method.
3) The variables created using #property are public. The variables defined in your class declaration (using #interface in the header file) can be declared as private to that class, using the #private keyword.
John, these questions are pretty basic. You would probably get a lot out of the Objective-C Programming Intro here ( http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Introduction/introObjectiveC.html#//apple_ref/doc/uid/TP30001163 ).

Using self in method call

When using property/synthesize for a UITableView, UIButton, etc should self be included in the method call on that variable? Using UITableView as an example is there a difference between [self.myTableView visibleCells] and [myTableView visibleCells]? Or say [self.myImage setImage:...] and [myImage setImage:...]?
I've seen Apple code that does use self (Bubble Level) and examples in the book Beginning iPhone Development that do not use self. I'd like to understand this better, especially since using self in my UIScrollView method calls has caused erratic/buggy scrolling behavior. Thanks.
Using self.myTableView is another way of saying [self myTableView] (it can also be [self setMyTableView:...]; if used in an assignation statement). In other words, you're executing a method.
Using myTableView accesses the instance variable directly.
Personally, I generally prefer using the former method, since it usually frees me from manually managing memory and gives me the benefit of KVO notifications. However, there is the miniscule overhead of the extra method call, which you may wish to avoid.
Which style you choose to use is up to you, and each way has its benefits and disadvantages.
The difference comes down to how you define the property. For example, say you have the following:
#interface MyObject : NSObject {
NSObject *memberVariable;
}
#property (nonatomic, retain) NSObject *memberVariable;
#end
#implementation MyObject
#synthesize memberVariable;
#end
Specifying (nonatomic, retain) actually tells #synthesize how to create the getter and setter methods. Specifying retain causes the setter method to call retain on objects I pass to it. So, self.memberVariable = someOtherObject is equivalent to memberVariable = [someOtherObject retain];
This is also why you should never do self.memberVariable = [[NSObject alloc] init]; if you've specified retain in the property definition. alloc initializes the retain count to 1, passing the object to the setter method increases the retain count to 2.
This comes down to whether or not your accessor methods have custom behavior, in which case you'd always want the accessors called even from within the class, and whether you want to make sure KVO notifications are generated. If you're using stock accessors (e.g., synthesized) and it won't affect anything to access the instance variable directly from within the class, you're saving yourself a method call.

How to share an array between two classes?

I want an array that gets data from one class to be avaliable to me in another class with the same data.
If we declare an array on the applicationDelegate class.
Then declare an object of applicationDelegate in both classes.
And assign the array into appDelegate.array from one class, will i be able get the array across the classes?
I'm with Mike. Leave the App Delegate out of it.
You're in control of when and how your objects are instantiated. If it's important for more than one class to have access to the same data, hand off the data, or a means of getting at your data, as you create instances of the dependent class.
An example, given classes WVParent and WVChild.
WVParent has a property, someArray, which is the array your other objects need:
#interface WVParent : NSObject {
NSArray *someArray
}
#property (nonatomic, retain) NSArray *someArray;
#end
Then you have WVChild, which itself has a property called parentObject:
#class WVParent;
#interface WVChild : NSObject {
WVParent *parentObject;
}
#property (nonatomic, assign) WVParent *parentObject;
#end
Assuming the parent is creating the child instance, you'd allocate it and assign the parent:
WVChild *child = [[WVChild alloc] init];
child.parentObject = self;
Then the child instance can access someArray by:
self.parentObject.someArray
This is just one option. You could also just pass the array itself to the child, assuming the data is static and unlikely to change over the course of the application session.
This way, instead of having a source of data living somewhere in the App Delegate, it lives within a class more appropriately responsible for its creation, maintenance and vending. If you've got a class that pops into existence and can only reach the rest of your app by getting the app delegate, you might want to put a little more thought into your architecture.
More on dependency injection here:
http://en.wikipedia.org/wiki/Dependency_injection
Yes, you could declare a member/property on your applicationDelegate class, although you should try to follow the Single Responsibility Principle and make sure you don't end up stuffing lots of miscellaneous shared stuff in your app delegate (which happens a lot with iPhone code).
Another alternative would be to inject the array into the objects' constructors when you create them.
It's hard to know the best solution in terms of design without knowing what this data is and where it really belongs.