1. Welcome to the new MacRumors forums. See our announcement and read our FAQ

Basic Objective-C Questions

Discussion in 'Mac Programming' started by xShane, Feb 11, 2013.

  1. xShane, Feb 11, 2013
    Last edited: Feb 11, 2013

    macrumors 6502a



    I'd currently classify myself as a beginner with regards to Objective-C programming on the Mac. I've done some Java but it's been awhile. I've just finished reading a book oriented towards beginners of Objective-C in order to obtain a simple grasp of the language. I've also done a few Xcode Objective-C based tutorials on the internet.

    I had an idea for an application that I could possibly benefit from via using, and it's also a very simple (or so it seems) idea. Nothing too advanced. I've been developing it for a few days now and it's been a great learner's experience so far (I prefer to get my feet wet).

    As I've been working on this simple app, I've had a few questions arise. Right now I'm doing all my code through the provided AppDelegate header and implementation files. I'm assuming this is acceptable for basic applications with not too many needs. However, as it get more "advanced" (I have lots of different category features planned), should I look into tying my interface-based app to other files, for better organization? Can I still connect outlets and actions to these other non-Delegate files, too?

    Also, I'm assuming that I should never access variables declared in header files directly, and that I should use the appropriate getter and setters provided from @synthesize? For example, I enter text in a field, and click a button. I then assign the string in the text field to a variable. I should use a setter instead of directly setting (i.e. variable = string), correct?

    This brings me to one last question. I noticed when designing my user interface I have two possibilities when "linking" objects to code: Outlets and Actions. I define and use outlets when I want to access/use/set that object via code (i.e. setting a text field within my code by calling _object setString:string;, etc). _object has to be an outlet to do this. I use an action when I want to connect a method/function to the object. Am I doing this correctly? My app has a lot of text fields to be set and I notice after awhile I have a ton of outlets "spamming" my header file. For now I organize my outlets into categories/windows using comments.

    Thanks for being patient.
  2. macrumors 6502a

    I generally create a new subclass of NSObject as my application's main "controller" logic. Keep the logic out of the app delegate and only use the pre-created app delegate for setting things that are specifically needed in that delegate. Then I use Interface Builder to create an instance of the controller object. Once that is done, you can connect UI elements up to your controller as needed. This is for basic apps. If you end up having multiple windows or pop-ups, then you can create more controllers to go along with them.

    If you need special data model objects, you can create more classes to deal with them as necessary.

    Remember, you connect outlets and/or actions to instances of objects. Not classes. IB can create instances of classes if it makes sense to do so.
  3. xShane, Feb 12, 2013
    Last edited: Feb 12, 2013

    macrumors 6502a


    Thanks for your input. I understand what you're saying.

    I did some further research on Application Delegates and Objective-C/Cocoa interface-based applications and see that the App Delegate should only be used for application-level stuff. I think what I'll do (for now) is have a separate file for all outlets/actions which then call methods from a set of "core" logic files. I now have to change the controller(s) and migrate/fix some code, but I'm learning so much :)

    EDIT: So you're saying a new view controller per Window/pop-up? Do you also create new '.xib's per view controller? I'm still a bit new to file organization.
  4. macrumors 6502a

    Of course, the answer is always "it depends". For something like a modal dialog box, there are already Cocoa routines to create those and return the user response. So you wouldn't need a separate controller for that. Standard dialogs (open file, print, etc.) already have standard Cocoa calls.

    For non-modal, do whatever makes sense. I once wrote an app that would allow the user to bring up multiple little stopwatch windows. In that case, the user could start several of them. So I put the window and controller for the stopwatch in a separate xib. Each user request to start a new stopwatch instantiated a new window/controller pair from that "stopwatch" xib.

    But if you have an optional extra window where it's showing or not showing (like, say, a high score window) then you could just add it to your existing xib.

    Different problems call for different solutions.
  5. macrumors 68040


    There are some who don't do this and will disagree with me, but you should always use the appropriate getter and setters instead of accessing instance variables directly. The only exception to this is inside the implementation of a custom setter/getter (where you have to do direct ivar access of course), and inside initialization (init) methods. Apple's document on encapsulation in Objective-C explains all this (and more).
  6. macrumors 6502a


    Yeah that's what I thought. I thought I read somewhere that Apple might even reject your app if you access directly.
  7. macrumors 68040


    They won't reject it. It's just a matter of good programming practice and style. Anyway, it would be pretty difficult for them to detect. Still, it's definitely good to get in the habit of always using accessor methods.
  8. macrumors 68000


    "Never" is kind of a bad word. There are exceptions to almost everything. One important one is that you might create an object that contains ivars that are not directly accessible to other objects, in which case you would probably not use @property in the first place.

    Consider, for example: you create a queue manager object. The object would probably contain a NSMutableArray to hold the queue, but other objects would not be able to actually see the array, they would only be able to add and pull entries, and possibly clear the queue. In this case, I would see no good reason not to access the array ivar directly from your object's methods.

    @property/@synthesize offers two important functions: one is that setter methods can transparent broadcast a notification to other interested objects when the property changes, tremendously reducing the amount of coding you have to do; the other is that accessors are typically thread-safe, unless you specifically mark the properties otherwise.
  9. macrumors 68040


    While, I agree that there are exceptions, as I mentioned in my reply, I still think one should use accessor methods even for internal/private values. You can declare an @property in a class extension to keep it private (just like any other methods). Your example is actually a fairly common scenario. You may not want public access to the underlying mutable array, but it's quite common that you want Key Value Observing (KVO) to work for the associated property. It's a lot easier to make sure this works right if you always call the setter when setting it.

    Minor nitpick: Accessors are atomic by default, but that's not the same as truly thread safe. It simply means that a if one thread calls the getter at the same time another thread is calling the setter, the getter will return a non-garbage value. It doesn't prevent race conditions (e.g. two threads trying to write a different value simultaneously), nor does it guarantee data integrity in the case that multiple properties interact with each other.
  10. macrumors 68000


    It occurs to me that Apple has implemented some form of "mobility" for objects, meaning that the pointer for an object may actually be an indirect reference, akin to the classic Mac "handles". This would explain why they are encouraging the use of accessors, because object context (ivars) may no longer be always at a consistent address. By using accessors instead of direct references, code maintains forward compatibility. Is this correct?
  11. macrumors 603

    Apple's own sample code occasionally accesses ivars directly. In some places, for instance C callbacks found in some of the iOS frameworks, this is required. There are also potential performance differences.
  12. macrumors member


    Objective-C is a really elegant and fun language to learn and use, and Xcode has evolved to the point where tricky things like memory management and tracking down bugs has become a fraction of the burden it once was.

    App Delegate:

    There's no theoretical reason why you can't write all your code within the app delegate -- after all, even if you write a program made of a hundred files, they're ultimately concatenated into one file anyway. But, in the interest of creating code that's clear, intuitive and reusable, Apple will tell you to follow the "Model View Controller" design pattern.

    "Views" are the kinds of objects you manipulate in Interface Builder -- designed to perform highly standardized tasks and reporting them through Actions to their Targets, but otherwise have no innate intelligence.

    The "Model" is the object that stores the custom data relevant to your app -- like a deck of cards and the order they're in -- as well as custom methods designed to make it easy for other objects to ask about or modify that data.

    "Controllers" are the intelligent link between Views and Models. Tasks for a Controller could be summarized by phrases like, "the user just tapped the 'take a card' button, so I'll call the method in the Model that provides the name of the next card," or "now that I have the name of the next card, I'll display that name to the user in the appropriate view." (Confusingly, a "View Controller", such as an instance of UIViewController, is a "controller." It's called a "View Controller" because it's responsible for managing a View, as well as the subviews it contains. Anyway.) Typically, you should start a new project an Xcode template that already includes some kind of UIViewController object. I would suggest -- just to nurture habits -- that even if you write all your code in one place, you do it in the implementation file for your main View Controller.

    Anyway, that was a huge answer, but I hope it gives you some kind of vague orientation. The enormous advantage of the Model View Controller pattern is that, if it's done properly, you could -- for example -- reuse the model elsewhere with entirely different views and controllers with virtually no trouble. You're *already* using view objects that have been designed with this kind of reusability in mind.

    With the templates available in Xcode, simple apps may not even need to modify the App Delegate file. However, you can use it to handle things like changes related to the app's state when the user is multitasking.

    Outlets and Actions:

    View objects use Actions to call methods that you write in code. Almost always, they call these methods to report on some interactions with the user. Your code uses Outlets to access the views they point to, usually in order to adjust and configure them in response to that interaction, or to changes in your Model. Put another way, messages sent with Actions go in the direction from the user to your code, and messages sent using Outlets go in the opposite direction: from your code to the user.

    Directly accessing instance variables:

    Having accessor methods and property declarations is usually preferable to accessing instance variables directly. There's never any harm in using accessors, even when the entire business of doing so is hidden within an object's implementation. In your case, yes -- use code like "self.variable = string" instead of "_variable" = string.

    I've found there's almost never any need to declare instance variables in header files -- you should think of header files as something presented publicly to other people (or to anthropomorphize, other objects in your program) with the goal of exposing clearly and at a glance, the competencies of the object. If there are instance variables that are necessary to the operation of the object, but not necessary for other objects to know about, they can be declared at the top of the implementation file using a Category. Other objects should *never* access an object's instance variables directly -- instead, those variables can be exposed in the header file using property declarations.

    Getting the most out of Objective-C really depends on your understanding of the concepts its developers had in mind. There are a two great resources to continue orienting yourself:

    - Stanford's "Coding Together" course on iTunes U. Even the first class session will help a ton and help demystify some of your main questions.

    - Apple's documentation. It's designed to be understood, and it's extremely rich and well-written. It's worth wincing and spending a couple of minutes really trying to understand each sentence and paragraph at first, and the documentation for some of the classes provide good models on which you can base your own header files before starting to implement them. It includes a lot of articles on the basics of Objective-C, as well as tutorials and programming guides that walk you through most of these good habits.
  13. macrumors 68040


    No, this is not correct. The pointer value will always be consistent for a given object instance. Besides, objects are always accessed by pointer anyway. Even direct ivar access is actually self->ivar after compilation, where self is a pointer to the structure representing the object whose method is being called. However, direct access can have implications for code forward compatibility.

    Not everything in Apple's sample code should be taken as the best way to do things. It's written by a variety of different Apple employees, and widely varying coding styles can be seen across authors and through time.

    There are some rare cases where direct ivar access is required in API-driven C callbacks. The only one that comes to mind is callbacks on Core Audio's real time rendering threads, where any calls into the Objective-C runtime are a bad idea. Generally, in a C callback, you can pass in an object pointer via the context info parameter, then cast that from void * to the object type in question, and send it messages (call methods).

    Direct ivar access is very slightly faster, but the difference is so small as to be irrelevant except in the most extreme situations. In any case premature optimization is a bad thing. If you profile your code and find that accessor method calls are really the bottleneck (again, very rare), then you could think about switching to direct ivar access, but you shouldn't disregard the disadvantages of direct access for some hypothetical, unlikely performance benefit.

Share This Page