iOS - Outlets in Category implementation files - objective-c

Overview
I have a iOS project in which the view controller implementation which has become large and thought it would be better to break into categories based on the functionality
The outlets in the view controller implementation file are not available in the category's implementation file.
Note - I am using ARC (automatic reference counting)
Question
I have an outlet to the textfield created in my view controller's implementation file. Now can I create another outlet to the same text field in my view controller category's implementation file ?
Would it cause any memory not be released or any other memory issues (Both the outlets are going to be weak and non atomic) ?
Is this acceptable from a design perspective or is there a better way to do it ?
Can category's methods be accessed in view controller's implementation ? I can include the header file but I want to know if at runtime there would be any unpredictable behavior

If you need to access declared IBOutlet properties in the categories of your view controller class, why not declare them in the class header file so that they are available to your categories? The ability to declare properties and ivars in implementation files now is meant to hide messy details of your implementation, but not at the risk of making your code unmanageable. Your functional design seems sensible.

You can have as many outlets as you want, they are pointers that will allow you to modify the object trough them.
If you are using arc and assuming you used the Interface Builder to create your text field then no, since you set them to weak it just means that these pointers wont count towards the retain count of the object, so the object will be kept alive as long as at least 1 strong pointer points to it. in this case the Interface builder's view is retaining it, when that view is deallocated so will the object be. Being non atomic means that its not tread safe but this doesn't matter for your purpose.
It really depends on your program, since i cant picture it with your description i can only advice into trying to stick to the MVC model when developing on iOS.
https://developer.apple.com/library/ios/#documentation/General/Conceptual/CocoaEncyclopedia/Model-View-Controller/Model-View-Controller.html

Related

associate model data pointer with NSWindow

I have a MacOS appkit app with a LOT of different NSWindows (hundreds), and they are each created from storyboards.
Many of these NSWindows have container views with complex embedded view/view controller hierarchies.
During initialization, it's necessary to know the model object associated with any given NSWindow, so its subviews and controls can be properly initialized. Since any NSController can know its NSView, and any NSView can know its NSWindow, it would be nice for that information to stored with the NSWindow.
It would be great to set a "representedObject" for the NSWindow, but unlike NSViewController, it doesn't really have one.
Is the only real solution to create a simple custom class (derived from a small base class) for each and every NSWindow storyboard object, so NSViews & NSViewControllers down the view hierarchy can get to my model data (pointer)?
A CLARIFICATION: very few of my NSWindow objects in our hundreds of storyboards have custom classes or code derived from NSWindow. So while a Category is definitely helpful for adding an API to classes to ACCESS the model data associated with the NSWindow, it's not helpful in creating a property or instance variable and initializing it in all those NSWindow storyboards.
ULTIMATELY I PRESENT A SIMPLE BUT DISGUSTINGLY BAD SOLUTION NO ONE SHOULD COPY:
Our app does not use NSDocument, which would provide a facility for associating NSWindow objects with a document/model architecture. So our goal has been to allow each and every NSController and NSView to get access to the appropriate singular document model object required to initialize the view's controls.
I've been warned by Apple engineering gurus that I cannot depend on the order in which views and subviews are created and initialized. That makes passing data down into complex storyboard embedded subviews tricky and error-prone.
But -- with all UI on the main thread, it is not possible for a single application on MacOS to create, initialize, and display one storyboard AND have another storyboard initialization & display interrupt that process (at least not our user-invoked application storyboards). So the simple solution is...
...to have a temporarily set application-level global with the desired document model pointer. That, and a stack-based lock count to insure that the above assumptions are never violated. Terrible design. Efficient solution.
No one needs to remind me WHY this is not good. But if there's a better solution it has escaped my testing. I found that even viewDidLoad and viewWillAppear can't be trusted to have a solid pointer back to its NSWindow...
Without knowing your application structure; you will need a mechanism to assign the model pointer to each individual window. This will necessitate adding some code somewhere. An NSWindow subclass does seem appropriate.
In the AppKit MVC pattern, model data usually fits between the view and the view controller. Attempting to associate the model with the window is fighting against this pattern to some extent.
That being said; the Objective C runtime does allow you to add custom properties to existing classes using categories. This is achieved using Associative References. The relevant functions are:
objc_setAssociatedObject
objc_getAssociatedObject
objc_removeAssociatedObjects
This article has a good rundown of the benefits and downsides of that approach.

Obj-C Pattern & Object Memory footprints

In this particular cocoa project I have properties for a set of views and there respective subviews being parsed from an xml file.
Only one view in the set is active at a time and the views may change frequently.
Would it be best to
A.) Initialize the view objects with the parsed properties and store a reference to them in an Array to be used when necessary.
b.) Initialize an NSObject with the parsed properties which can in turn create it's respective view upon demand via a factory.
The logic behind this is that the NSViews not being used (majority) could be deallocated by ARC when needed as they would not have a persistent reference.
This begs another question.
Is all of this done in the background anyways (Since NSView is an NSObject subclass) when an NSView is referenced but not being displayed?
You are describing implementing your own version of xibs. I'm going to say, the "best" answer is reconsider your design decision. There is probably a better and easier way to achieve your desired result.
The memory difference between an array of NSObjects describing all the properties and subviews of a NSView versus an array of NSViews is nominal.
The most memory efficient way is to lazily deserialize the single view through a NSWindowController or NSViewController.

Connecting actions works. Connecting outlets doesn't

I have a XIB file with my controls in it, loaded in the Interface Builder (Xcode 4.0.2 on Snow Leopard).
The file's owner is set to, let's say, the someClassController class, and I've also added (in the Interface Builder) an NSObject instance of someClass, as well.
I've managed to link e.g. a button with an action in someClassController or someClass - and it works for both of them.
However, whenever I link an outlet to ANY of them, it fails to show up; and NSLog reports NULL pointers.
Hint : My issue here could be much more complicated than it seems, since both my someClass and someClassController classes inherit other classes, which inherit other classes and so on (I'm dealing with a huge-to-chaotic codebase, and I don't really know what else could be helpful to post)... However, I would still like to hear your opinion on what might be going wrong in such a case...
When you see problems like this, it's almost always because you have more than one object of the kind that has the outlet. The one in the nib whose outlet you connected is not the one that is examining its outlet.
To investigate this, add statements in the object's initializer method(s) and possibly awakeFromNib to log the value of self.
Some (or all, or none) of the objects may be created in nibs, and some (or all, or none) of them may be created in code; objects in the latter group won't trip awakeFromNib, since they didn't.
Either way, once you've inventoried what instances of the class you have, you can kill them off until you're left with the ones you want.
To add to Peter Hosey's answer, and after reading some more details in the other question you posted about this issue, here are some other factors to consider:
The File Owner class selected in the nib is completely ignored at runtime. It's there only for design-time convenience – for checking available actions and outlets.
Is there any chance you're finding nil pointers in -init? Outlets are connected after -init and before -awakeFromNib. They'll never be connected in -init.
I'm trying to understand the sequence of initialization (from your other post). It sounds like you are creating a new instance of your CTTabContents subclass, and passing it to your CTBrowserWindowController subclass's -addTabContents: method. Then the CTBrowserWindowController loads your objects from the nib.
Or, maybe that's wrong. You might be creating a instance of your CTTabContentsController subclass. Then that object is loading TabContents.xib.
It's important to track down where the nib is being loaded and which object is being provided as the file owner at that time.
Another question: are you using manual release/retain, automatic reference counting, or garbage collection?
Finally, I reiterate the importance of printing out the self pointer in your initialization methods. In addition to -init and -awakeFromNib, try other initialization methods like your CTTabContents subclass' -initWithFrame:. When you're discovering intermittent null pointers in the rest of your debugging, print out the self pointers then, too. You'll probably be seeing different values of self then, too.

When do I need to subclass UIViewController and when can I just instantiate it?

I am learning iOS programming through the Big Nerd Ranch guide by Hillegass and Conway. I’m writing an app of my own as I go through the book, and one of the questions that has been bugging me is exactly when I need to subclass UIViewController (and its ilk) and when I can just instantiate it.
For example, my app consists of generic building blocks: the interface is tabbed, and the tabs lead to a UITableView, a UINavigationController that creates UITableViews, and so on. Following the book’s instructions, I have subclassed UITableViewController to create the table views. However, in creating the UITabBarController that contains all of my app’s content, it seems sufficient to instantiate a UITabBarController and then add a bunch of views to it. (All of this is done in the application:didFinishLaunchingWithOptions: method of my app delegate. Since most of my app consists of simple combinations of basic UI parts, I’m trying to do build the UI programmatically whenever possible.)
I get the impression that what I should be doing is creating a subclass of UIViewController (or UITableViewController or whatever) for every interface in my project. This seems weird to me, since most of these classes would only ever be instantiated once. Am I just misunderstanding how OO should be used in this case? (I have a good amount of programming experience but relatively little has been with OOP.) Should I be creating a subclass for each and every screen that the user will see?
Should I be creating a subclass for each and every screen that the user will see?
If each view requires different logic, yes.
Don't shy away from creating new classes for conceptually separate things. Programmers coming from non-OOP to OOP might feel that a file with only a small amount of code is a waste. Suppress this feeling. Classes are cheap, and help enormously to organise your thinking.
So you have two types of UIViewControllers in iOS. "Container" viewControllers and "Content" viewcontrollers. Both are subclasses of UIViewController but have very different purposes.
The Container type is what the UINavigationController and UITabController are. They are rarely subclassed and typically used as is (in fact, I believe Apple doesn't allow the subclassing of UINavigationController at all). These "Containers" take care of moving "Content" view controller around for you. They do not have much content of their own, beyond adding things like a tab bar or a navigation bar.
The "Content" view controller are the ones you create most of the time. You will rarely be able to use a UIViewController as is, because it will not have any functionality. That is why you subclass them. These are meant to represent a single "screenful" of content. So in effect, every "screen" the user sees should be controlled by a UIViewController subclass.
The UITableViewController is simply a specialized sublass of UIViewController that already contains some methods for managing tables.
The way the UIKit framework was designed was for you to use subclasses of UIViewController to display content and to use out-of-the-box "Container" controllers to facilitate the management of your UIViewController subclasses.
You need a subclass of UIViewController if you want to do any of the following (not an exhaustive list, but some examples)
customize the view hierarchy when the view hierarchy is loaded (in
viewDidLoad)
provide some behaviour as the view controller's views become visible
(or not) (in viewWillAppear:, viewDidAppear:, viewWillDisappear:,
etc.)
clean up after yourself as needed in viewDidUnload
create outlets to views in the hierarchy so you can adjust them as
needed in the above lifecycle methods
My reasoning behind subclassing UIViewController, and other classes is that:
Almost always you must initialize variables and assign values to the instances of classes. You add subviews and set their frames, define actions for the UIViewController instance, etc. If this UIViewController instance is directly from the base class, its initialization should be done outside of it. If this initialization is required at different places for multiple times, you may have to deal with repeated initialization process.
So, you've compiled these processes into a method, making it reusable from wherever this UIViewController instance is used. But where do you want to put it? Don't you think it's much better to put it inside the subclass of UIViewController? Also, you don't even have to come up with specific name for this initialization method. Just override the default -(id)init from the super class.
Though you may think it's suffice to use UIViewController without subclassing it for now, as your project grows, it will be challenged to deal with reusability issues. Take some time to look at your codes. Check if there is too much repetition for such as initializing an object, or assigning values to it. If you are doing same things with an instance of a class in multiple places, compile them into a method to be reused. And as number of such methods grow, you will find the need to use subclass which will contain these relevant methods for the instance.
No matter the size of your project, using classes to distinguish different objects is important. Almost always, the basic essential classification is done by the framework, making it unnecessary to introduce new concept for a class. However, this doesn't mean the framework also knows how your project and its objects can be classified into. By using subclass, you can utilize every benefit the development framework can provide and still keeping the objects in your project to be as unique as possible, based on the purpose you've designed for them.
Well about the UITabBarController you are right. There is no reason for you to subclass anything if the default behavior is sufficient. However once you need to do some custom things you will need to subclass it..
Also, why are you trying to build the GUI programmatically? For the learning curve? There is no real reason not to use InterfaceBuilder, it saves you a lot of time.
You should subclass the UITableViewController in order to get your data in the view, that is how the MVC model works. The default implementation does not offer anything in order to get your data in the view, I don't think they will ever do that in order to make sure that nothing is wasted, their 'connection' to the model object might be different from the one you want and you would end up writing an adapter if your model object is not compatible.
I hope this will help you out a bit.
And merry x-mas.

Using Protocols in Objective C to Transfer Data Between Different Objects?

Hey guys, I currently have a root table view which has a toolbar at the bottom and has labels and a refresh button within it, much like the Mail app's toolbar. This root table view controller obtains data from a server by allocating and initializing a DataUpdater class. Within this class are the NSURLConnection delegate methods that are called while communicating with the server.
As you can probably guess, I need to know when certain (delegate) functions are called within the DataUpdater class and the values of the parameters passed to these delegate functions so that I can update the labels on the toolbar accordingly (i.e. Connecting..., Updated, etc).
The problem I am having is determining how to notify the root table view controller of what is going on in these delegate methods. Would I use protocols, if so how? I have been skimming the documentation and don't quite see how I would get this effect. Or would you suggest I implement my program another way?
Thanks in advance!
A protocol is a kind of contract that says: I promise to provide the non-optional methods defined in the protocol, and maybe even the optional ones. It's purpose is like Java interfaces: to work around missing multiple-inheritence.
The delegate pattern in Objective-C normally works like this: you define a protocol, and then in your class, you define a variable like id<MyProtocol> myDelegate; and define a setter and maybe getter (either via normal methods, e.g. - (void)setDelegate:(id<MyProtocol>)aDelegate; or via properties.
Note that the delegate is not retained ! So if you work with a property, you need the assign option, not retain.
Now back in your class, you check whether myDelegate is nil and if not, you can directly call its non-optional methods. If you want to call an optional method, you first need to verify its presence via respondsToSelector:.
So if you decide to use the delegate pattern, you need to define a protocol, add that protocol to your root table view controller, implement the necessary methods there, and make sure to call [foo setDelegate:self]; or something similar to inform your other class that the root table view controller is the delegate. And of course implement the delegate calls in your class.
Edit:
An alternative might be to use NSNotifications, BTW. The advantage of notifications is that you can have multiple objects listen and react to them. The disadvantage is that you cannot (directly) pass values back. For example, you can define a delegate method that asks the delegate whether to do something or not. That's not possible with notifications, it's more like shouting into a room instead of having a one-to-one conversation.
DarkDust's answer about protocols is fine but I would like to add some things to it.
One underlying thing that is often forgotten when it comes to delegation is object ownership. When a program is running it creates a tree of objects. Its root object is the application delegate and for example it owns a navigation controller, which owns the individual view controllers, which own the view and the view owns its subviews and so on.
Often the question comes up: "Why is the delegate not retained, just assigned?" The problem is that if you send a message to a deallocated object the program crashes. So how do you make sure the delegate stays around? The answer is object ownership.
I give you an example: a UITableView and its data source which is the TableViewController which is nothing but a delegate. The TableViewController holds a reference with its view property to the UITableView, so it owns the TableView. That means when the tableView is alive there must also be its parent object present, which is the UITableView's delegate. So there is no danger that the delegate goes away somehow.
In the end it is again all about memory management.
Take home message is: think upfront about object ownership will make your program mode modular, easier to maintain and will lead to a looser coupling between individual objects.