Given that iOS SDK 6.1 is used in Xcode 4.6.3 , does it make a difference to declare the method signature of IBAction in a header file or not?
Without putting the method declaration in the header file, the app is still able to compile and run without problems. However, the method cannot be seen in a storyboard.
Are there any hidden issues of not declaring the method in the header file? Is there a memory consumption difference?
The entire point of an IBAction method is to be a public connection point in Interface Builder (using Storyboards or not).
The word IBAction itself is #defined as void. Its only purpose (and the same is true of IBOutlet) is to allow Xcode to scan your code and find these points where your controller needs to be wired up views via IB. You don't need the IBAction part of the declaration if you're programmatically connecting a control to that method.
There's no performance difference, but semantically, putting an IBAction in your implementation file doesn't really make sense. Having an IBAction means the controller is communicating to an outside object via that method, and that's exactly what header/public #interface declarations are for.
Only declare it in the .h file if you want to connect it in your storyboard/interfaz builder or you want to make it public for other classes to call it.
If you just want to make it private and only use it inside your class, there's no need of declaring it in the header file.
There's no memory or performance difference.
Even if you plan to hook it up to the interface builder, it still doesn't have be in the header file. I personally just place them straight into the implementation file.
Related
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).
I noticed this while using iOS6 beta 3
When I create a new subclass of a UIViewContoller (no other parent classes generate this behavior that I've noticed), the .m file now has an empty category at the top of the file. In the past when learning about categories I noticed that some people would use this same technique to indicate private methods (although not truly private).
Is that what the intent is here? Has there been any change to making things actually private now? I notice the #private directive out there too.
What is your person coding style regarding private vars and methods?
UPDATE: Since XCode is pushing us to use the class extensions, I went ahead and used them for private methods/ivar for this project. I found a drawback though. I saw that I could reuse one of my subclassed UIViewControllers along with all of it's UIButtons, UILabels, etc.... I had this inheritance:
UIViewController <- FirstViewController <- SecondViewController.
Well, all of the private methods that I put in the class extension of FirstViewController do not pop up in the autocomplete when I code in SecondViewController. A slight annoyance....
You're referring to this interface definition:
#interface MYViewController ()
#end
This is technically a class extension rather than a category. Categories have a string inside the parentheses. Class extensions are added to the class at compile time, and so can add ivars (usually in the form of properties). Categories are added at runtime and cannot add ivars.
All that said, your point is correct. This is used to define private methods and properties.
In the ObjC world, "private" is a "no trespassing" sign, not a razor-wire wall. While there is a #private keyword (that adds compiler enforcement), it only applies to ivars, and generally isn't necessary. This type of warning-based privacy works very well in ObjC and is quite sufficient.
Put your private properties in this class extension, and outside callers will get "may not respond to selector" warnings if they try to access them (just like they would get for calling any undefined method). You should never allow warnings to exist in an ObjC project, so this enforces data encapsulation.
EDIT
If they're private, then they shouldn't pop up in your subclass. What you want is protected. There's no great scheme for protected methods in ObjC, but a common technique is to put them into a category in a .h file like MYViewController+Protected.h. I find this comes up very seldom in practice, since so much of good ObjC design doesn't subclass. It uses composition and delegation instead.
Regarding "Why just view controllers." First, it's not just view controllers. It's just view controllers on iOS (well, VC, TableViewController, and GLKViewController). On Mac, it's also window controllers and spotlight importers. Look in:
.../Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Templates
.../Library/Xcode/Templates
But why those? Well, those are all controllers, and it's insanely common for controllers to need private properties. In fact, if you don't have private properties in a controller, you're probably making too much public. That's not as universal of model and view classes. I suspect that played into their decision. It might also have been different people who owned the templates, or that they were updated at different times. Sometimes you see little inconsistencies that smooth out over time.
You can make your own templates as well. See Creating Custom Xcode 4 File Templates.
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.
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.
I've got two controls in my Interface Builder file, and each of those controls I've created a separate delegate class for in code (Control1Delegate and Control2Delegate). I created two "Objects" in interface builder, made them of that type, and connected the controls to them as delegates. The delegates work just fine. My problem is, I need to share information from one delegate to the other delegate, and I'm not sure how.
What is the best way to do this? Combine the two delegates into one class, or somehow access a third class that they can both read? Since I'm not actually initializing the class anywhere in my code, I'm not sure how to get a reference to the actual instance of it (if there is an actual instance of it), or even access the "main" class that the project came with.
You can add outlets from either delegate to the other delegate. There are two ways to add an outlet to an object in IB (assuming you're using Xcode/IB version 3.0 or later:
If you have not generated the code for your delegate classes yet, select the desired delegate, then open the "Object Identity" tab in the IB inspector. Add a "Class outlet" of type NSObject. You should then be able to set this new outlet to the other delegate. Of course you will have to generate the code for your delegate class and add the generated source files to your Xcode project before you can load the nib.
If you've already generated the code for the delegate class (or added an NSObject to your NIB and set its Class to an existing class in your Xcode project), add an instance variable to the delegate class:
IBOutlet id outletToOtherDelegate;
As long as your Xcode project is open (as indicated by the green bubble in the lower-left of your NIB window), IB will automatically detect the new outlet and allow you to assign it to the other delegate object in your NIB.
Cocoa automatically connects these outlets at NIB load time. Once awakeFromNib is called on instances of your delegate objects, you may assume that all the other objects in the NIB have been instantiated and all outlets have been connected. You should not assume an order on calls to awakeFromNib, however.
I think you can create outlets on each one and cross-bind them so that they each have the same data all the time. If there's one model object they need to share, that's pretty tidy. I don't actually know how to do this; I think I saw it in an iPhone tutorial one time!
I don't have my Mac in front of me currently since I'm at work, but would it be possible to bind an instance of one delegate to a member of the other delegate? This would be similar to binding an NSArrayController to a member of another controller class, for example.
However, depending on what the delegate classes are doing, if the tasks are similar I would probably just combine them into once class. That would eliminate the problem altogether.