How to initialize custom classes in ViewControllers? - iphone

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.

Related

iOS Singletons and Memory Management

I'm certain that I'm missing some fundamental understanding of iOS memory management and, despite lots of reading and searching, I'm still not getting it.
I use a singleton in my app that has info about the user currently signed into it, info accessed from multiple view controllers, etc. It has multiple ivars that are get and set throughout the app. They're declared and propertied in the .h file like so:
NSString *myString;
and are made retained like so:
#property (non atomic, retain) NSString *myString;
and synththesized in the implementation.
I get and set their values in methods in the singleton like this:
myString = #"value";
and
methodLocalString = myString;
In other places I include the singleton -- call it CurrentUser -- I import it:
#import "CurrentUser.h"
Outside of the singleton I get and set it like this:
[CurrentUser sharedCurrentUser].myString = #"Bob";
and
myOutsideString = [CurrentUser sharedCurrentUser].myString;
Most of the time this works great, with the values appropriately persisted from one getting or setting to another. The trouble is that sometimes when I get them that way I find that they've been released (crashing the app), which NSZombieEnabled thankfully tells me.
What I don't get is how his can happen. I thought the singleton was never released, and that therefor retained properties of the singleton would never be released. I'll note that the problem seems to be more common with non-real-object properties like NSDate and definitely-not-object properties like int and BOOL which can't be retained, but it happens with object properties as well.
What am I ignorant about here? And thanks for your patience.
Your problem is:
I get and set their values in methods
in the singleton like this:
myString = #"value";
When you assign directly to the iVar, instead of using the property syntax (self.myString = #"value"), you are bypassing the synthesized setter method, which means that the retain never happens.
Properties aren't magic. They're just a bit of syntactic sugar for the "." access, and the ability to have synthesized getter/setter methods to save you the tedium of writing your own.
self.myString = #"value";
is just shorthand for
[self setMyString:#"value"];
The synthesized setMyString method will do something like:
if (myString != newValue) {
[myString release];
myString = [newValue retain];
}
(assuming retain option on the #synthesize)
Don't use singletons. Your current problem is caused by a simple memory management misconception, but the singleton pattern will only give you more headache in the long run.

Would it be correct/ellegant use only alloc without init?

If we don't want to implement init method in our class, and bearing in mind that init in NSObject only returns an instance of the object without initialization, I don't see the point of calling init if we already get the instance with alloc. I have tried and it works, but I am not sure it won't cause future problems.
myClass *newObject = [myClass alloc];
instead of:
myClass *newObject = [[myClass alloc] init];
Thanks a lot.
No, just calling alloc would not be correct. alloc zeroes out all instance variables of the object, init then has the chance to set all or some instance variables to their default values. Some classes even use their init methods to create another instance and return that one instead of the one you allocated.
Many classes expect that their init methods get called and would possibly cause crashes if you don't call init. If you are talking about a custom class that inherits directly from NSObject and needs no initialization of instance variables, you might get away with [myClass alloc] but it is definitely not good programming style.
I think that it is not a good idea.
Read Cocoa Design Pattern, especially the "Two stage creation"
You can also read this article http://www.informit.com/articles/article.aspx?p=1398610
I think that it wouldn't matter much if you didn't implement a "- (id)init" because if you did, you would call NSObject's init method which just returns the same value you send to the method. Though it is a good idea to create your own init method to set your instance variable.
in runtime source code
perform -(id)init will call _objc_rootInit(self) and will return self. I guess only perform init is OK。

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 do I reference a pointer from a different class?

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;
};

How to tell if an object has already been allocated, so it isn't allocated multiple times?

Please be nice.. I am a noob with this stuff. I want to allocate and use an object through a method that I call many times, and instead of making it a global variable and allocating it in my initWithFrame method I want to alloc it in just the one method, and make it a local variable that I allocate then and use then.
You need to step back and think about how many different things need to access said object.
If it is everyone, then you should likely implement the shared instance pattern. Something like:
+ (MyObject *) mySharedObjectThatEveryoneUses
{
static MyObject *sharedInstance;
if (!sharedInstance) {
sharedInstance = [MyObject alloc];
sharedInstance = [sharedInstance init];
}
return sharedInstance;
}
Note that the above does not account for threading on initialization. I.e. if multiple threads simultaneously call the method for the first time, you might end up with multiple instances. Also note that the splitting of +alloc and -init is a pattern that is unique to this situation. Doing so avoids the situation where the -init method causes + mySharedObjectThatEveryoneUses to be invoked, creating a second instance before the assignment can happen.
Now, if you are talking about access within an object graph; access to the single instance within some subset of objects in your application, then you will need to have an instance variable somewhere that all of the objects can get to.
For example, say you are implementing a game where there is a Player object and that Player object has a bunch of Piece instances. When a Piece is created, you would typically have a property that refers to the owning player and that would be your single point of reference.
If you need something more transient, you should likely look to what should be your controller layer. I.e. there has to be some object somewhere that can act as a coordinator for the set of objects that need access to that single instance.
If I understood your question correctly, you're looking for a static variable. A static variable keeps its value like a global variable, but it "lives inside" a function like a local variable. Your function could look something like this:
+ (MyObject *)getSingletonObject {
static MyObject *obj = [[MyObject alloc] init];
return obj;
}
obj would be created the first time you called this method, but calling the method again would return the same object it had already created.
What you want is called a Singleton. You can read up on Apple's recommended way to create singletons here:
http://developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/CocoaObjects.html#//apple_ref/doc/uid/TP40002974-CH4-SW32
Look for "Creating a Singleton Instance" in the "Cocoa Objects" section. There are a few more methods it's good to define beyond just a class level initializer.
I'm not entirely sure I understand your question, but you can't really allocate the same object many times.
Each time you want a new instance, you ask the Class object to allocate a new instance for you (yes, classes being objects themselves is mind blowing). So this code:
NSString* s;
s = [[NSString alloc] init];
s = [[NSString alloc] init];
Here you are creating two instances of NSString. This code is bad because we have alloc'd the first instance and have not released, and assigned its only reference (s) to a new instance. This would cause a memory leak.