How do I reference a pointer from a different class? - iphone

First off, I despise singletons with a passion. Though I should probably be trying to use one, I just don't want to. I want to create a data class (that is instantiated only once by a view controller on loading), and then using a different class, message the crap out of that data instance until it is brimming with so much data, it smiles.
So, how do I do that? I made a pointer to the instance of the data class when I instantiated it. I'm now over in a separate view controller, action occurs, and I want to update the initial data object. I think I need to reference that object by way of pointer, but I have no idea how to do that. Yes, I've set properties and getters and setters, which seem to work, but only in the initial view controller class.

There's no need to use a singleton if you don't like the pattern or if it doesn't fit. Assuming you are creating your second view controller in the first one, just declare an ivar and property for your model object in your second view controller and when you instantiate it, assign the model object to this property.

Make a global variable for your object and store it there on creation. You can wire that up in the init method (probably bad style), or from the caller or via interface builder. Just make your variable known in the files that use it.
Or - well - use some kind of singleton pattern and get the instance directly from that class. Looks much cleaner.

Seriously use a singleton. In case you don't like them cause you don't know the code:
#interface Order : NSObject {
NSMutableArray *order;
}
#property (nonatomic, retain) NSMutableArray *order;
+ (Order *)sharedInstance;
#end
#import "Order.h"
#implementation Order
#synthesize order;
+(Order *)sharedInstance {
static Order *myInstance = nil;
#synchronized(self) {
if(!myInstance) {
myInstance = [[Order alloc] init];
}
}
return myInstance;
}
-(void)dealloc {
[order release];
[super dealloc];
}
#end

Um. Hello. Isn't Core Data a good enough framework for you? It allows you to have a single persistent store and multiple contexts to manage updates and merging of changes in response to notifications. I may be out of line here, but seeing how you start the question with a strong opinion about a well accepted pattern in your first question indicates that you have not spent much time discovering the ways in which the objective c runtime and Foundation classes in iOS can collaborate to achieve a task. In any software, one object and only one object owns a specific resource. You should embrace singletons. I suggest you spend some time reading http://www.cocoadesignpatterns.com/. Oh yeah, check out the meaning of KVO.

Why not make it a property of your app delegate? That way you don't have to use the singleton pattern but you are taking advantage of Apple's already existing usage of the singleton pattern.

Don't forget that Objective-C is a superset of C.
Basically, a data class is a plain C struct.
If you want to access a variable of that class from another class, make it global.
mydata.h:
struct MyData {
// Whatever data fields that you need, e.g.:
NSInteger value;
};
extern struct MyData mydata;
mydata.c:
struct MyData mydata = {
// Whatever initial value that you find relevant, e.g.:
.value = 42;
};

Related

How to initialize custom classes in ViewControllers?

I'm still trying to wrap my head around how to best create and init custom classes in several ViewControllers.
Let's say I create a MyData class.
In FirstViewController, I wish to initialize it.
From one of the iPhone classes at college, a teacher suggested to use the following so that several instances of the same object are not created.
#property and #synthesize myData is done
-(MyData *)myData {
if (!myData) {
myData = [[MyData alloc] init];
}
return myData;
}
myData is released
Three things with this. If I put a MyData alloc init in one of the FirstViewController's methods, then I'm told every time that method is called, a new object is created which is consuming memory and is a potential for memory leaks. By creating the above getter, every time the object is used, the getter is called which seems like a waste of CPU cycles. If I don't do an alloc init, then the object is not created at all.
Lastly in subsequent views, I find I can get by just doing #property and #synthesize MyData in SecondViewController and then pass the myData object in the FirstViewController to it.
So why do I need alloc init to create the object in FirstVC and not in the SecondVC? Shouldn't I need to do that to allocate some memory for the object to be created so I can send in the reference?
Is there a better way of alloc init the object myData in the FirstVC that doesn't create multiple instances yet doesn't unnecessarily waste CPU cycles? (For those thinking CPU is cheap, what if you had many objects declared and think mobile)
Hope this makes sense. Thanks in advance,
Hiren.
I'm not sure I can fully resolve your confusion, but here are a few ideas to consider:
First, don't worry about the load on the CPU associated with using property accessors. If that's where your bottleneck is, either you're doing very well or your app isn't doing very much. It's great to be conscious of potential performance issues; it's not so great to fix them before you know that there's really a problem.
Second, why not just initialize your properties in your -initWithNibName:bundle: method? Like this:
-(id)initWithNibName:(NSString*)name bundle:(NSString*)bundle
{
if (self = [super initWithNibName:name bundle:bundle]) {
myData = [[MyData alloc] init];
}
return self;
}
The code you showed looks a bit like what one might use to create a singleton, i.e. a class that can only be instantiated once. Could that be what your teacher was talking about? It's not something you need to do most of the time.
I'm not sure how to address your issue with the second view controller... I think there's some more confusion there, and since we don't have any code to talk about, it's hard to proceed. If you're using the "modern" Objective-C runtime, you can declare properties without providing matching instance variables, and perhaps that's what you're doing, but you still need to initialize your properties before you use them.

Extending existing classes by adding instance variables

in Objective-C if I need to add additional method to UIButton I can use Categories for that. Is there any easy way (except subclassing) to add additional instance variable or property (instance variable + getter/setter).
Let's say I want to store UIColor reference in UIButton.
PS: It is mor theory question. I already implemented that using subclassing but looking for "nicer" way.
Thanks.
One solution is to use associative references; not as fast as ivars, but quite useful.
I.e. given:
#interface UIButton (color)
#property (nonatomic, retain) UIColor *myPrefixColor;
#end
You could implement this as:
#implementation UIButton (color)
static const char *assocKey = "myPrefixColor associated object key";
- (void) setMyPrefixColor: (UIColor*) aColor
{
objc_setAssociatedObject(self, &assocKey, aColor, OBJC_ASSOCIATION_RETAIN);
}
- (UIColor*)myPrefixColor;
{
    return objc_getAssociatedObject(self, &assocKey);
}
#end
The myPrefix stuff is because you should never add methods to existing classes without prefixing 'em with something such that the chance of a collision with an existing method (that you aren't aware of) are minimized.
You cannot add ivars using categories.
I don't think it's possible to add ivars to classes to which you don't have the source. Two technologies come close: Categories let you add instance methods, but not instance variables, and class extensions let you add instance variables by declaring properties, but the compiler enforces the implementation of those properties' methods from within the implementation block of the class, which you don't have access to. They're designed to aid the implementation of private interfaces, not really extend classes that already exist.

What are alternatives to "delegates" for passing data between controllers?

Are there alternatives to "delegates" to pass back data from one controller to another?
Just seems like a lot of work implementing a delegate just to pass back the result from a child controller, back to the parent controller. Is there not another method? Are "blocks" one answer, and if so some example code would be great.
Delegates aren't a lot of work, aren't a lot of code, and are commonly the most appropriate solution. In my opinion they're neither difficult nor messy.
Five lines of code in the child's interface. Before #interface:
#protocol MyUsefulDelegate <NSObject>
- (void)infoReturned:(id)objectReturned;
#end
Inside #interface:
id <MyUsefulDelegate> muDelegate;
After #inteface's #end:
#property (assign) id <MyUsefulDelegate> muDelegate;
One line of code in the child's implementation:
[[self muDelegate] infoReturned:yourReturnObject];
One addition to an existing line of code in the parent's interface:
#interface YourParentViewController : UIViewController <MyUsefulDelegate>
Three lines of code in the parent's implementation. Somewhere before you call the child:
[childVC setMuDelegate:self];
Anywhere in the implementation:
- (void)infoReturned:(id)objectReturned {
// Do something with the returned value here
}
A total of nine lines of code, one of which is merely an addition to an existing line of code and one of which is a closing curly brace.
It's not as simple as a returning a value from a local method, say, but once you're used to the pattern it's super straightforward, and it has the power of allowing you do do all kinds of more complex stuff.
You could use many ways:
Calling a method of the super controller, needs casting maybe
Notifications
Simple Key-Value-Observing
Core Data
Example for for 1.
interface of your MainViewController: add a public method for the data to be passed
- (void)newDataArrivedWithString:(NSString *)aString;
MainViewController showing ChildController
- (void)showChildController
{
ChildController *childController = [[ChildController alloc] init];
childController.mainViewController = self;
[self presentModalViewController:childController animated:YES];
[childController release];
}
Child Controller header / interface: add a property for the mainViewController
#class MainViewController;
#interface ChildController : UIViewController {
MainViewController *mainViewController;
}
#property (nonatomic, retain) MainViewController *mainViewController;
Child Controller passing data to the MainViewController
- (void)passDataToMainViewController
{
NSString * someDataToPass = #"foo!";
[self.mainViewController newDataArrivedWithString:someDataToPass];
}
KVO or notifications are the way to go in many cases, but delegation gives a very good foundation to build upon. If you plan on extending the relationship between the view controllers in the future, consider using delegation.
Blocks are not really relevant to the above, but in short - it is a technique introduced with iOS 4, where you pass around blocks of code as variables/ parameters. It is very powerful and has many uses. For example, here is how you enumerate objects in an array using a block:
[someArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop){
NSLog(#"obj descriptions is - %#", [obj description]);
}];
The part from the ^ until the } is a block. Note that I've passed it in as parameter. Now, this block of code will be executed for every object in the array (i.e. output will be the description of each object).
Blocks are also very efficient performance-wise, and are used heavily in many new frameworks.
Apple's blocks beginners guide is quite good.
Check out NSNotificationCenter — NSNotificationCenter Class Reference
Folks pay a lot of attention the the V and the C in MVC, but often forget the M. If you've got a data model, you can pass it from one controller to the next. When one controller makes changes to the data stored in the model, all the other controllers that share the same model will automatically get the changes.
You might find using a singleton is practical. Just use it as a central storage for all your shared data.
Then throw in saving the state of your application too;)

Global Objects iphone

What is the easiest way to create a global object. I have tried declaring the object outside the method with no luck.
#implementation UV_TouchpadViewController;
NSMutableString *string = [NSMutableString stringWithFormat:#"text"];
Very close -- you can't initialize a non-local variable with a non-const expression, and a method call is inherently non-const, even if it looks like it should be. So basically, change it to
NSMutableString *string;
but if it's only going to be used inside the implementation file (eg. other classes would only get at it through UV_TouchpadViewController, not get/set it directly (this is also the recommended pattern)), then qualify it as static, like so
static NSMutableString *string;
If on the other hand you do want to be able to access it directly from outside UV_TouchpadViewController, leave off the static, but add
extern NSMutableString *string;
to your header file (outside the class #interface), and whomever includes the header will be able to access it. (Note that you could instead just put NSMutableString *string; in your header file, however this is quickly becomes unclear)
Also, if you are trying to do this for a singleton class, (I can't think of a good reason to have a global mutable string -- you know they're not thread safe right?) I recommend reading Apple's docs on singletons first, where they suggest you use ivars, not global variables, even for singletons. However, UV_TouchpadViewController should not even be a singleton (if it is in any way a view controller), it should just have a single instance, if that's all you want.
If on the other hand you just want all UV_TouchpadViewControllers to have access to this one variable, note that across almost all languages this is considered a bad design pattern (globals are bad), and that you should instead stick it in, say, your app delegate (which is guaranteed to have a single globally accessible instance), where it can be an ivar+accessors, and generally considered a setting and (with a little extra code) persisted.
EDIT:
If you want to have a singleton that maintains global state, which I still recommend against -- you should create a class, like for instance ApplicationState, which handles all of the application's global state as a model object in the traditional model-view-controller pattern. I wont go into detail here because that would be highly redundant of a google search.
In your Application Delegate, somewhere, add an ivar ApplicationState *state, and a corresponding #property (and #synthesize in the implementation file).
There are few easier ways to shoot yourself in the foot than by using global variables.
You should never expose a dumb object like a string which has no access control to every object in the app. Any random piece of code anywhere in the app can change the mutable string leading to chaos as the app grows larger.
Usually when people want a global variable what they actually need is either the user defaults or a data model.
The user defaults (NSUserDefaults) is the preference persistence system that saves application state and user's settings both between launches and as the app runs. You can park small bits of data, such as strings, in the defaults and access them easily from anywhere in the app.
A data model is dedicated object that holds the applications data and manages access to it such that only the data model has final control. This makes it easy to tell what has changed the data and how. The data model can be a simple custom class or something elaborate such as core date. You can park the data model in the app delegate or create it as a singleton as the other answered have explained.
I have been using the Apple API for years and I have never needed to use a real global variable. If you think you need one, you probably have misunderstood something about application design in the Apple API. You might want to post a question explaining what you're trying to do with a global variable and what the best strategy should be for doing it without the dangers of using a global variable.
Do you need it for each instance of the class? If so, you should make it an Instance variable. Put
NSMutableString *string;
In your header
And then you can set it in any method in your class.
If this isn't what you meant, update your question or comment.
You can achieve that by implementing getter and setters in the delegate class.
In delegate .h file
Include UIApplication delegate
#interface DevAppDelegate : NSObject <UIApplicationDelegate>
NSString * currentTitle;
- (void) setCurrentTitle:(NSString *) currentTitle;
- (NSString *) getCurrentTitle;
In Delegate implementation class .m
-(void) setCurrentLink:(NSString *) storydata{
currentLink = storydata;
}
-(NSString *) getCurrentLink{
if ( currentLink == nil ) {
currentLink = #"Display StoryLink";
}
return currentLink;
}
So the variable you to assess is set in the currentlink string by setters method and class where you want the string ,just use the getter method.
AppDelegate *del=(AppDelegate *)[[UIApplication sharedApplication]delegate];
TO set:
[del setCurrentLink];
TO Get:
NSString *value=[del getCurrentLink];
All the best
Add:
NSMutableString *globalString = nil;
to any .m file of any object. The nil initialization adds a little safety, since nil objects can be "safely" messaged without outright crashing the app.
Add:
extern NSMutableString *globalString;
to the headers of any other objects that needs to access this global.
Add:
if (globalString == nil) {
globalString = [ [ NSMutableString stringWithFormat:#"text"] retain ];
}
to the init of any class(es) that could be the very first to touch this global, or to some init that happens even earlier.
Globals are a less verbose form of singleton, but with no access restriction or tracking. Use with caution.
actually as per my r&d i got that by use of extern we have to create an instance but the final thing is to #define your variable and can access any where you want without any creating of instance and other thing just directly use variable by its name....

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.