XCode/Cocoa Objective-C - A couple questions - objective-c

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.

Related

Using separate .nibs and getting logic out of App Delegate

I have a document based app using the standard template. I have two auxiliary panels in Main Menu.xib, and my main logic is currently in the App Delegate, mainly through an IBAction in App Delegate triggered by a button on one of my panels. Everything works fine, but I know it should be organised better.
I have implemented a Preferences panel as suggested by Hillegass in Chapter 12. So:
Create a custom controller called AppController containing instance
of PreferenceController. This is instantiated in Main Menu.xib
Custom PreferenceController class which is subclass of
NSWindowController. This loads the Preferences.xib
Preferences panel created in Preferences.xib
Before I get too far in the app’s development, I want to be sure I’m organising things the right way.
I want to move my main logic out of App Delegate, possibly into App Controller. I want App Controller to be in charge of showing and hiding the various panels, and I want each panel to have its own .xib.
I have created two more subclasses of NSWindowController and made them ivars of the AppController, alongside the PreferencesController eg. Panel1Controller & Panel2Controller.
My problem is that interface builder is not letting me connect an IBAction in AppController to a button on one of my panels. It only lets me connect to the .xib file’s owner, i.e. Panel1Controller in the case of Panel1.xib.
If I put the logic in Panel1Controller, how do I get at one of the other panels (say Panel2Controller?) in order to hide it?
Am I going about this the right way?
Getting very confused….
Any help much appreciated!
Regards,
John
Just for simplicity sake I'd move all the nib elements controlled by the NSWindowController sub-classes out of the main nib and into nibs with the same name as the (NSWindowController) sub-classes that control them. DON'T expose IBOutlets or IBActions in the sub-class headers (they should be in a class extension ("#interface MyWindowController ()") in the source file for that sub-class.
Also, is the AppController a 2nd app delegate? Probably not what you want (there can only be one); you should merge its logic into the existing app delegate if that's the case.
I just came across this method.
This seems to do away with NSWindowController altogether, and make the AppController the file's owner of both .xibs. This way IB allows you to create outlets in AppController for each window, and contain actions.
I have created a very simple, two-window app using this method that hides one window when a button on the other is pressed. Before I go away and re-organise my main app, I want to be sure I'm doing this the correct, standard way, if there is one?
This page contradicts this method, by saying one window = one .xib + one NSWindowController subclass.
If you do it the latter way, how can one window talk to another, when you can't create outlets/actions in the AppController? Actions implemented in a window's NSWindowController class can't see outlets of another window, so how can they communicate?
This seems like pretty standard, basic stuff and yet I cannot find any sources which say which way is correct/best practice.
Another method I have read about here mentions using Notifications.
I'm still wondering though - which is the most common "accepted" method of loading two or more windows in separate .nibs and getting them to talk to each other? I'm surprise this info has been so hard to find.
If you're going to follow this pattern, separate AppDelegate and AppController, then your MainMenu.xib should not contain any window objects of any kind...it should just contain the application menu. Each additional window (NSWindow/NSPanel, etc.) gets its own .xib and its own NSWindowController.
There are two ways to assign references to your properties (IBOutlets) and methods (IBActions): 1) programatically, 2) via Interface Builder. Let's cover the second method!
To be able to wire things up from Interface Builder (IB) you will need a reference to the target object inside IB. For the MainMenu.xib file, this gets setup automatically: the MainMenu.xib contains an "AppDelegate" Object reference. The Object reference exposes the properties and methods in the AppDelegate class that are prefixed by the "IBAction" and "IBOutlet" macros. I write Object (with a capital O) because it is a widget available in the "Object Library" in IB.
You can easily create an instance of a custom objects inside a .xib file (via IB) by dragging an "Object" widget from the Object Library into your .xib. Then set the Object's class to that of your custom class. Once you've done this, the IBActions and IBOutlets in your custom class object will be available in IB. [Note: one thing to remember when doing this, is that when you load the xib, the object will be instantiated automatically. No need to alloc and init from within AppDelegate...you still have to call showWindow: on it].
As you mentioned, another approach is to simply have all of your additional .xib files owned by the AppController. That would be convenient, but it also gets 100% away from the architecture that you were trying to follow in the first place. In other words, if you're going to follow that style, why not just skip the separate AppDelegate and AppController in the first place, and just stick with the former (which would then be a Controller and Delegate).

Why Apple's sample code project IKImageViewDemo does not have an AppDelegate class?

I have studying how to use IKImageView in my app. I downloaded the following demo from Apple site.
https://developer.apple.com/library/mac/samplecode/IKImageViewDemo/Introduction/Intro.html#//apple_ref/doc/uid/DTS10004049
One thing I do not understand is: This project has only implemented a Controller class.
#interface Controller : NSObject
{
...
I do not understand how does it work at all. If I create a new project in XCode, it will usually generate an AppDelegate class which implements NSApplicationDelegate interface.
I do not know if I understand the mechanism correctly.
Does the following steps describe how it works?
1) In info.plist it specifies the main bundle is MainMenu.xib.
2) the Window is binded to the Controller like so
3) When the application starts, it loads the Windows from the MainMenu.xib and the Controller class takes over the windows interaction from there.
It's really old sample code. It predates Xcode project templates generating an app delegate for you.
Back then, early Xcode and ProjectBuilder (the old name for it)
Left it up to you to do that.
Lots of older sample code has this sort of thing. As long as things get kickstarted by nib loading, magic happens, objects are instantiated and connected
If you have a simple controller that inherits from NSObject and it has a proxy in you main nib file, it will get created. If you also connect its proxy as delegate to some view or control in the nib, all of that happens.
You don't technically need an object that is the delegate of you NSApplication object. But in reality it is a good best practice and any non trivial app will have that and a lot more.
There's a lot of magic that happens when the C function NSApplicationMain() is called at the launch of your app.
The old and in many ways out if date book Cocoa in a Nutshell covers this well.
Yeah you pretty much describe how it works and what it's doing.
It's relying on the fact that NSApplicationDelegate is an informal protocol and it doesn't declare that Controller conforms to it and is using the NIB to kick-start the app.

How to force interface builder (storyboard) to generate controller initialisation code?

I am getting incredibly frustrated with interface builder at the moment, and would appreciate some help before I ragequit it and code everything by hand (which seems to be much, much, much easier).
The basic situation is this: I need to make a model variable accessible to each view controller in my application.
The simplest way I can see to do this is to just create a property on the view controllers that retains the model, and to set that after the controller is initialised.
However, I can't find any of the actual initialisation code for the views shown on the storyboard in my project. There's no reference to any of them at all. Does the interface builder really generate not generate any code reference to its controllers in the app delegate?
For that matter, why is there no reference to any of the top level controller objects (tabview, tableview etc) in code at all?
All I want to know is how to force xcode to actually generate the controller creation code in AppDelegate.m - so that I have access to the created instance of the controller - or, failing that, a way to share the model between these amorphous objects.
Maybe it would be easier to create a singleton class where you can store all your global variables and methods. Example here.
You will need to manually create a subclass of your view controller and then override the methods you want to inject code into. In Interface Builder you can then choose to make your View controllers of this custom type.

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

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.

split iphone objective-c code in to multiple files

I have written a few apps for the iphone now, but they are all written in what I consider to be a lazy, unstructured way.
I have started a new project and have created several Objective-C classes (subclass of NSObject). the problem I have is getting the logic correct in my head. My structure is as follows
viewController.h
viewController.m
plotPoints.h
plotPoints.m
handleFeeds.h
handleFeeds.m
So the main file is the view controller and I include in it's header file the other classes. My problem is that in the other class files, eg plotPoints.m - if I try to refer to a variable I set in the view controller, it says it's not set. I have included the viewcontroller in the plotPoints.h file - but still it doesnt work.
what is best practice for separating code in this way? In this example, I have webservice feeds which I want to handle in one class, then process those results in another and handle the main UI in the view controller.
Thanks for any information.
I say the Controller shouldn't be referenced by your - as I understand - external classes (plotPoints and handleFeeds, by the way these should definitely begin with an uppercase character).
Actually, it should be the exact opposite, your viewController should be using methods and properties of your external classes. PlotPointsand HandleFeeds should not have to refer to instance variables of your Controller, let it pass them as arguments for you methods instead.