Can I convert a non-xib app to use xibs? - objective-c

I have a working app with a navigation controller, two view controllers, two views, a model object, and no xib file. The views are created programatically. Now I'd like to build the same app using IB and xib files. Does anyone know of a writeup that explains how to add xib files and delete the program statements they replace? If not, then something that discusses the equivalences between xib library elements and program statements?
Why do I want to do this? Because I'm trying to understand what xib files do and how they interact with program statements and I thought this would be a good learning exercise. I made one try at it but couldn't get it to compile. In fact, every time I use xib files, except following textbook examples, I get hopelessly tangled up in code that won't compile or doesn't work if it does compile. So I must have some basic misconception. I need to figure out what xib files are doing behind the scenes. They seem potentially very powerful but I won't use them if I don't understand what they're doing.
I read elsewhere in stack overflow that they are a serialized version of a compiled view (or something like that). I understand that conceptually. I'm thoroughly familiar with Python's pickle files. But that doesn't explain much in practice.

A nib/xib contains the information needed to create and connect objects together. Basically, it contains instance variable and class information for the objects it contains. To load one, you use the UINib class (NSNib in Mac OS X), or the NSBundle loadNib… methods. NSBundle's methods are easier to use, and I would suggest using them unless you will load a nib several times. For iOS, you would typically use [[NSBundle mainBundle] loadNibNamed:#"NibNameWithoutExtension" owner:self options:nil];. The owner does not have to be self. It is the object represented by the "File's Owner" object in IB and will receive any connections made to that object. The options parameter can be used to get the top level objects in the nib, but you usually use outlets instead. When a nib is loaded, the objects inside it are allocated and instantiated (using initWithCoder:), and connections are created using setter methods, or by setting the instance variables directly.

Related

Multiple instances of an object inside a XIB file

I have a document-based app with the recommended NSDocument / NSWindowController setup. Every window has its own NSWindowController instance and an associated XIB file. The interface is loaded pretty straight-forward in -(id)init: if (self = [super initWithWindowNibName:#"DocumentWindow"]) { // yadda yadda }. The XIB file contains an object that represents a separate controller that should be instanciated every time the user opens a new window. It presents data that is only relevant to the current document. When I unpack the object with -(id)initWithWindowNibName: I always get a reference to the same instance despite having two different window controllers and despite having called -(id)initWithWindowNibName: twice. The XIB loading mechanism seems to only unpack the same archived object once which kind of makes sense (really?).
Is there no way besides allocating separate objects in code, manually loading views, calculating their sizes, adding them as subviews, then setting bindings and keeping an eye on unbinding them manually when the window gets closed?
I’m banging my head against the wall, because of my own stupidity. It just makes things worse.
As I initially thought I was absolutely on the wrong path. The issue was simply that I registered a notification in the aforementioned instantiated class for an object that was a subview of the application’s keyWindow (I hacked it together and wanted to change it later to a property, ouch). When the application was loaded all instances registered for all document windows and all of them got notified and calculated the same data.
The debugger is my best friend today.
There is actually nothing like an optimization when you unarchive objects from a XIB and you will always get different instances (which absolutely makes sense in retrospect). If you encounter a similar issue, then it’s probably an unrelated bug at another place in your code.

Access the same object inside two different nib files

I want to know how the same reference of an object of a particular class can be accessed inside two different Xibs.
I understand that by creating an object reference for the class inside each xib creates different objects. Even when using AppDelegate its creating different objects.
What I want to achieve is that referenced object inside both the xibs should be the same (so that I can use the object as the datasource of two different table views for instance.)
Only create the object once, and put it somewhere you can get to it from both classes. For instance, you could create the object as a property of your application delegate. Then add
AppDelegate *app = [[UIApplication sharedApplication] delegate];
to your classes (after importing AppDelegate.h) and access the object with app.objectName.
The other answer will work but it's a bad design.
You should stick to the tell don't ask rule. Give your objects the dataSource you want them to use, do not have them asking for a dataSource, which is actually a nasty global.
The other issue is your understanding of nibs. They store an object graph, when a nib is loaded the graph is un archived and each object in it is instantiated. If you have two of the same objects in the graph then you will end up with two instances not two references to one instance. It is the same for when you drag out multiple views, you end up with multiple instances of UIView (and subclasses) which is exactly what you would expect.
It's well worth the effort in learning the boundaries between what you can/can't do in a nib and what you have to do in code and how they all fit together.
Interesting !
Try using singleton approach, check out this link http://www.duckrowing.com/2010/05/21/using-the-singleton-pattern-in-objective-c/
Using this approach, you can create an instance which will be available throughout the application life cycle

How to use classes to control windows in Objective-C

I have been making applications for Mac with Objective-C for about a year now but due to not really understanding how to use classes properly I have only ever used the 'AppDelegate' files. I want to start using classes as soon as possible because from what I understand it's very bad practice to clump it in to one class. Basically, how do I have two windows, each controlled by it's own class. I understand how to make objects similar to NSString or something but don't understand how to have classes that control windows etc.
Thanks
Edit: Basically I want to know how to split up my application in to classes.
If I understand you correctly then you need to create individual controller classes sporting their own IBOutlets and IBActions and hook these up to your UI elements. To split up an existing application into smaller classes requires some knowledge of Object Oriented programming.
Alternatively, you might benefit from reading this (or a similar) book:
'Cocoa Programming for Mac OS X' by Aaron Hillegass.
Try looking for NSWindowController in the docs. You create a custom subclass of NSWindowController and a xib file for it. In the xib file, make sure you set the class on the File's Owner to your custom subclass, and make sure its window outlet is connected to the window in the xib. If all that sounds totally foreign, head for the books! =)
Then, in the code where you want to bring this window onto the screen, you create an instance of your custom subclass and associate it with the xib, like so:
MyCustomWindowController *controller = [[MyCustomWindowController alloc] initWithWindowNibName:#"myxib"]
[controller showWindow:self];
The xib loading system will hook up all your custom outlets and actions on the new controller, and you can show it or do other wonderful NSWindowController things.

XCode/Cocoa Objective-C - A couple questions

Sorry for the stupid post, but I am new to Objective-C programming and Cocoa and have a couple of questions which I can't find the answers to, I'm hoping someone can enlighten me.
Firstly, in XCode, when using the Interface builder, when I want to create a new object I drag the object to my 'assets'. However I can't specify methods or anything without manually creating a new class file. Is there any point using the interface builder's 'object'?
The first app I built to test things with, I put most of the code in the AppDelegate class files. Research has shown me that the AppDelegate's purpose is simply handling application events like launching and closing. Was I wrong in putting the methods in this class? Does it make any difference?
Finally, if I have several class files created, each handling their own functionality with an interface built and linked to the classes, then what do I do with the 'main' file? It seems to me that the 'main' file and 'appdelegate' class files will be for the most case left as-is?
I hope that makes sense. Again i'm sorry for the silly-sounding questions but I can't find any answers.
Thanks in advance everyone!
Firstly, in XCode, when using the Interface builder, when I want to create a new object I drag the object to my 'assets'. However I can't specify methods or anything without manually creating a new class file.
Sure you can. Just set the class of the object using the inspector.
Note that you can only connect nib objects to an outlet or action. You can't specify any random methods, nor should you—the whole point of the IBOutlet, IBOutletCollection, and IBAction keywords is to declare in code that these properties/methods are used by a nib.
Is there any point using the interface builder's 'object'?
Yes, but pretty rarely. Usually you create objects in code and connect outlets to them.
The application's delegate is one object you may want to create in the MainMenu or MainWindow nib, if you build your application that way (the iOS templates have changed away from it for some reason).
The first app I built to test things with, I put most of the code in the AppDelegate class files. Research has shown me that the AppDelegate's purpose is simply handling application events like launching and closing. Was I wrong in putting the methods in this class?
Probably. The application's delegate generally should only handle business relating to the NS/UIApplicationDelegate protocol.
On the flip side, it's OK to make your root view controller the application's delegate, if it makes sense to do so (and the NS/UIApplicationDelegate implementation code is not too voluminous). The question you have to answer—and only you can answer it for your application—is whether you are making your root view controller the application's delegate or the application's delegate the root view controller. If in doubt, keep them separate.
Does it make any difference?
Long-term, yes. It's very easy, especially in the class of the application's delegate, to create a Big Ball of Mud class—one without well-defined and clearly-delineated responsibilities. Take dynamite to such a class as soon as possible.
Finally, if I have several class files created, each handling their own functionality with an interface built and linked to the classes, then what do I do with the 'main' file? It seems to me that the 'main' file and 'appdelegate' class files will be for the most case left as-is?
Yes. They're boiler-plate.
If you haven't written any code in the application's delegate (or have removed everything you had put there into new and better-delineated classes), such that all that's left are empty method bodies or none at all, you can safely remove the application's delegate. You can always create it again later if you change your mind.
Note that if you delete your application delegate class, you should also change the main.m file—or the MainMenu/MainWindow nib, if you have one—to not refer to it. Your application won't build if your UIApplicationMain call (or any other code) refers to a class that doesn't exist, and it will crash if your MainMenu/MainWindow nib (or any other nib) refers to a class that doesn't exist.
There is no shame in your application having a delegate if you need it to, but if you don't, removing it and the class you were using for it eliminates future temptation to stuff code there or use it to store third-order globals.
The point of using objects in interface builder is to connect methods of the object to UI elements.
It partly depends on what your methods are doing, but for the most part the app delegate class is going to be left alone. It isn't an actual requirement (your program will work either way) but it is common practice because it generally creates more maintainable code. The app delegate should just handle the application events ( using other classes to do any complex logic or heavy lifting ).
The 'main' file will most likely not change. I can't think of any reason to do so, but I wouldn't rule it out for some advanced cases.
To be honest I only used the Object thing in IB once, when I wanted a separate object to have some UI bindings.
About the app delegate and main file, yes, you'll leave them as-is most of the time. But if you try to do something besides test apps you'll need to handle open events to, for example, connect to a server, ask the user for a review, increment some launch counter, etc... Those are just examples!
The main file I advise you to left it alone and use the object oriented tools provided. You should have a view controller hierarchy, isolate your views from the data, and use the view controller to comunicate between view and model. Read about MVC if you want more info on how your application should be organized.

How do you see or manipulate the code behind the views you create?

I'm trying to figure how to look at or manipulate the code behind views I've created in tutorial applications I've copied.
I understand that you are supposed to "control" the views using a view controller. The part that's confusing me is that when I follow the tutorials, I'm clicking on my view objects, setting the delegate, but I don't see where that is acutally happening in the code. Are you able to see the code that makes up a view or is that totally hidden from you?
You mean when you are dragging views around visually when you open a nib?
The objects you create and the connections you make are saved to an XML file. When Xcode builds your application, these are then converted to a more efficient binary file format.
When your application runs, the binary file is read, and the objects described within are instantiated. Where connections are made, the nib loading part of the platform uses Key-Value Coding to set the outlets and properties on related objects, most often the nib owner.
You can see the XML representation of your views by right-clicking on the nib in the project navigator panel on the left-hand side, then selecting Open As | Source Code.
You need to go through Apple's "Your First iOS App" guide, and read it, do it, and reread it until just that basic tutorial sinks in.
If you use Interface Builder to create a view (it will create that view in a nib file), you will connect that with a view controller that will consist of an interface file and an implementation file. Within these files you will place code by which you will reference those components in the view, and you will also code methods that will give you behaviors and operations that can be triggered or can manipulate components and data of that (or other) views.
You just need to really digest Apple's documentation better. They have wonderful guides to help you.