In most of the iOS SDK tutorials I've read online both from Apple and elsewhere, so many instance variables are made properties, even when they are only accessed from within their own class.
E.G. in Facebook's latest iOS SDK a user is encouraged to maintain an instance of the Facebook class called facebook in the app delegate. facebook" is a property. This is then referred to throughout the sample code as "self.facebook". But the "facebook" property is not referenced anywhere from outside the app delegate.
Why is this? What am I missing? If an instance variable is only used within its own class, my inclination would be not to make it a property so that it is not publicly visible, and refer to it simply as facebook rather than self.facebook or self->facebook from within the class.
Frankly, even if I needed the facebook property, I think I'd rather refer to it within the app delegate as simply "facebook" rather than "self.facebook".
So what gives? Why am I seeing properties everywhere?
Properties don't have anything to do with whether an iVar is publicly exposed or not. Instead properties create accessors methods that manage retention and foster encapsulation.
If you want a private property just declare the ivar under the #private directive and then define the properties in the implementation file.
One great example of why you should use properties (you can make properties private as TechZen noted), is creating new instances in viewDidLoad.
People do this all the time, because it's called once per instance of a view controller. Or, so you think... in reality because of what happens when you application gets a memory warning, a viewDidLoad class could be called multiple times per instance.
So for example you might well write code like:
- (void) viewDidLoad
{ myArray = [[NSMutableArray alloc] init]; }
Works great - until it's called again, then you have a leak. You could release myArray before you assign it just in case - but the trouble is that's an easy step to forget.
If you use properties for every instance variable though, then your code looks like this:
- (void) viewDidLoad
{ self.myArray = [NSMutableArray array]; }
Now you can't get it wrong. If viewDidLoad is called multiple times, the old array will be released and a new one will go in its place, without leaking the old array.
Usually it's better to access to the instance variable through an accessor, rather than directly. Properties create these accessors, and also provide things like proper key-value change notifications and atomic access.
Properties can generate getters and setters. Setters, in particular, can help manage retain/release counts of objects (semi)automatically, and thus reduce certain types of potential memory bugs.
Getters and properties for non-objects are mostly for orthogonality of coding style, although they do have potential to be used for mutators, key-value notifications, etc. in some future extension or reuse of the code.
There may be some efficiency differences/disadvantages, but that depends on the particular ObjC run-time in use.
if you refer to facebook, then it will access the variable directly, if you access self.facebook, then it will go through the setter/getter methods.
the result is that if you need to mutate an object or at somepoint later in time, you need to do other things during the process of changing the value(ie boxing it) then you can put this in the setter method and reduce having to do it everywhere. its a good thing.
It creates the getter/setter for you automatically.
Also, here is a good post explaining it properties
Related
I'm making an app for a final project for class and I need to share strings, integers and floats throughout different views in my application. I have to create an app that a waiter/waitress would use on the job. I need different views for different types of items to order (beverages, appetizers, entrées, etc.) and need to keep the items chosen, the price and the quantity of each accessible to different views to keep a running total available in each view (one view for each type of item) and finally for a view that displays an itemized list of what was ordered plus the total.
From what I understand I wouldn't want to use a tab bar application layout because typically users don't expect information to be the same between different tabbed views, so I was thinking of using a segmented controller for this. To get the strings, integers and floats shared between views could declare them in the AppDelegate? I've read that I could use singletons but we haven't covered that in my class so I think that may just add more complexity than I need. If I were to declare them in the AppDelegate would I have to synthesize them in the AppDelegateViewController.m to make them available throughout? I can't imagine I'd have to synthesize them for each different ViewController. Or would NSUserDefaults be perfect for this situation?
If I declared an instance variable in the AppDelegate would that essentially make it a global variable? I know that this is against encapsulation practices but that won't make a big difference with this app, it's not going to be in the App Store and the overhead shouldn't make a big difference considering this is going to be a relatively small app.
Thanks in advance everyone. Good luck with your finals if you still have them approaching!
Edit
I guess I should say that this is going to be a janky, terrible app off the bat, we didn't cover a lot of the more advanced topics such as the MVC paradigm for iOS so I'm pretty limited with what I can do compared to what we're supposed to do. Stupid class, I regret signing up for it when I really could have gone about this myself and gotten a better understanding of Objective-C, which we were taught nothing about, and a better understanding of the iOS framework.
Basically, if I declare the variables in the AppDelegate, even though it's a faux pas, would that work to access the strings and such from the different views? Or would the NSUserDefaults be a better solution in this case? I'm leaning towards NSUserDefaults and declaring them in the projects ViewController.
A typical Objective C MVC solution is to put all your related shared strings and variables into a Model object (create a new class for this object) as properties. Then share that Model object with all the Controllers that need to access those variables or strings.
Using the AppDelegate as a model object is "over-sharing", and clutters up the app delegate with non-delegate related stuff. A slightly cleaner solution is to have the app delegate hold a getter to a Model object that is widely used throughout the app. A solution that can cause code reuse problems, and is otherwise considered politically-incorrect, is to assign the model object, and/or the shared variables themselves, to C global variables (be careful with your retains). (But this usually generates the fastest and smallest amount of code, if you care about such things.)
As hotpaw2 said, using a distinct model class is the best way to go.
But, as this is a small app (while you are learning the basics) implementing these few variables in the app delegate wouldn't hurt and is perhaps a little easier.
If the app grows then you'll probably want to move the model out of the app delegate and into it's own class.
An even easier and simpler method would be to store this small amount of data in nsuserdefaults:
save to nsuserdefaults:
[[NSUserDefaults standardUserDefaults] setObject:howManyDrinks forKey:#"howManyDrinks"];
[[NSUserDefaults standardUserDefaults] synchronize];
retrieve from nsuserdefaults:
NSString *howManyDrinks = [[NSUserDefaults standardUserDefaults] objectForKey:#"howManyDrinks"];
You can utilize the facility of Delegation pattern using Protocols in Objective C.
You could also store these values in a plist, which can then be accessed and edited from anywhere within the app. It is easier to implement than a singleton. And since you can set the plist up visually in XCode, it's relatively easy for beginners. I even created a wrapper for my plist to make editing the data simple. Here's a tutorial for plists.
I'm not an expert in this yet, but I've been using a singleton, with an object inside. As far as I have experienced, the values inside that object is held. To create a singleton, you'd do something like this:
Create a normal Object, and add this to the header file:
+ (id)sharedManager;
Then in the .m file, add this:
+ (id)sharedManager {
static SharedInfo *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init {
if (self = [super init]) {
self.myStuff = [[NSMutableDictionary alloc]init];
//This is where you initialise your variables. The example above is for a
//property that I have declared in the .h file
}
return self;
}
And then, throughout your app you'd use this:
[[[SharedInfo sharedManager] myStuff] addObject: SomethingTocreate];
Make sure you include the SharedInfo.h in the viewcontroller that you want to use it in.
I hope this helped.
I'm building a shared manager inside my app what would be responsible for Facebook interaction.
I need a way for this shared manager to keep a reference to the view controllers who ask for it to do some stuff.
I obviously created some protocol that each such controller can conform to.
I can map in each method call, a FBRequest to a view controller, and when the request returns, look for the appropriate delegate.
I have 2 problems:
NSDictionary retain it's values, which I don't want to in this case cause it may cause retain cycles. Is there a way to tell NSMutableDictionary no to retain it's values ?
In the case where on of the delegate gets released I need to tell the manager not to forward any callbacks to that delegate, and actually to cancel any live requests.
Is it the right way to go over the dictionary values and erase the delegate.
For some reason it just doesn't feel right to go over the values instead of the keys.
P.S - I'm aware that if FBRequest had a userinfo property or a way to work with blocks it may be easier, but I'm curious to know how to solve it in the current situation.
Thanks
I have a UITextView that points to the File's Owner as its delegate, and I have a number of the delegate functions implemented. However, I would also like to point to a second object (in this case a TextExpander object, http://www.freshblocks.com/tutorials/how-to-add-textexpander-touch-sdk-to-iphone-apps/) also as a delegate. How might this be possible? As far as I know there can only be one delegate in objective-c.
I don't know the specific of TextExpander but he delegate design pattern assumes one and only one delegate. You can't have two delegates for one object.
There are ways around this. You could designate one of the delegates as the primary delegate and implement all the methods in this class. That class could then simple call the secondary delegate for the required methods. This is the simplest approach but does result in the primary delegate becoming tightly coupled with the secondary delegate.
Another approach would be to resolve the messages dynamically and use message forwarding. You would still require the a primary/secondary delegate pattern, but instead of the primary delegate needing to implement all the methods it would simply pass all messages it doesn't respond to onto the secondary delegate. This approach means that the secondary delegate can change by adding/removing additional delegate methods without having to change the primary delegate. The key method is - (id)forwardingTargetForSelector:(SEL)sel. See Objective-C Message Forwarding for a good explanation.
It seems that they solve this in step 5, by setting [textExpander setNextDelegate:self]; before setting the textExpander object as the "primary" delegate of the view.
I don't have the code myself so I haven't tried it, though, and their documentation is... well not.
Just for information: Delegates are not an Objective-C feature, but a design pattern using though Cocoa/Cocoa-touch.
Delegate pattern allow only one object to be notified of the changes of another. The solution to have an intermediate delegate object could be an easy way of doing things.
If you want to keep your code clean and reduce the coupling you might use another pattern known as KVO (Key Value Observing). Apple provides a good guide on how to use it.
In KVO a single object, that needs to be KVC (Key Value Coding) compliant, can notify multiple objects without even knowing about it. It uses an intermediate notifier object (singleton for you application).
Check the Apple doc on KVC + KVO and you shall be able to do what you want.
I have a class with the protocol NSXMLParserDelegate implemented. I call this ParserHelper. I parse a lot of XML which happen to have some tags in all of them and i have about 20 parsers (one for each type of XML), and i didnt want to implement it over and over again.
So, I subclassed my ParserHelper class 20 times, adding in each subclass the required tags/behaviours like CaseAParser, CaseBParser and so on...
I just implement the delegate methods i needed and called it on the superclass once i'm done with the method.
I assume it works on every delegate.
This way, all you need is to make your class a subclass of SMTEDelegateController and implement the methods you need, remembering to call the [super whatEverMethod:andParameters] at the end of your functions and you should be good to go.
Iam having a very basic doubt in memory management. If suppose iam allocating memory for an object in viewWillAppear method. Should i release the object in viewWillDisappear method or in the release all the objects in the de
It's dependent when you want to release the object. You don't have to release on viewWillDisappear. But, you can, just think about when you need it and when you don't. Technically, either one is fine. Depending on the situation though I would think: if you need the object for multiple views don't dealloc in viewWillDisappear, if you need it only for that view and you don't need it again, dealloc in viewWillDisappear.
Here's a very easy to learn tutorial on objective-c memory management.
http://cocoadevcentral.com/d/learn_objectivec/
You'll learn a lot about retaining and releasing variables. In general variables are defined according to scope (i.e where they will be used) For example, you may want to initialize a variable that's used throughout a class in viewDidLoad and release it in dealloc. It all depends on where you need to store data and for how long.
I'm developing an iPhone application, and I very new on iPhone development.
I've created some custom classes with instance variables (NSArray, NSString, etc.). All classes inherits from NSObject.
Should I create a dealloc method to release all instance variables?
Thank you.
Yes, you definitely need a dealloc if you are keeping instance variables that are objects. You will also probably need to retain or copy those as well, depending on how your object creates/uses them.
Check out this article on memory management. I think it explains it pretty well. You must also read the Memory Management Programming Guide for Cocoa. Even if you don't fully understand everything, read the whole thing through, then read the article, then do some work, get some crashes and read it again :) eventually it should all click.
In iPhone development its pretty much SOP to have a dealloc since there is no garbage collection.
You have to release any object your class has ownership for. That means, yes you have to overwrite the dealloc method and release the objects there.
Normally you have ownership over values (objects) in instance variables, but it also depends own how you create them.
You should definitely read the Memory Management Programming Guide, it describes pretty well when you gain ownership.
Yes, having a dealloc method is normally the best way.
If you want to reclaim memory used by your instance variables you will have to release them when you are done with them. You could add a method to do this clean up:-
- (void)cleanUp {
[myArray release];
[myString release];
}
Call it when you no longer need the instances.
Now, the chances are that the point in time when you want to release these variables is the point in time when their parent object is destroyed (parent object is gone, so instance variables are no longer needed). As -dealloc is automatically called for you when the parent object is going to be destroyed - it makes more sense to put the cleanup code in dealloc than in our -cleanup method that we have to call at the right time.
If you don't want to reuse the memory, eg. if you are never going to be finished with the instance variables, then you don't need to release them and might not need a -dealloc.