Archive for category Programming

Notes on Nib files and retaining IBOutlets

Nib files store the application’s user interface (views) in “freeze-dried” state. When you initialize a view controller with the appropriate Nib file, a copy of the outlet objects is created from the “frozen” one in the Nib file and the IBOutlet ivars in your class are hooked up to point to the newly created objects.

This unfreezing happens every time the view is loaded. Each time the view is resurrected in this manner it will appear like the original in the Nib file. So if you load a view and then make modifications (say change the layout) when the view is unloaded and reloaded, the modifications will not be visible.

From the resource programming guide:

“Nib files are the documents produced by the Interface Builder application. A nib file describes the visual elements of your application’s user interface, including windows, views, controls, and many others. It can also describe non-visual elements, such as the objects in your application that manage your windows and views. Most importantly, a nib file describes these objects exactly as they were configured in Interface Builder. At runtime, these descriptions are used to recreate the objects and their configuration inside your application. When you load a nib file at runtime, you get an exact replica of the objects that were in your Interface Builder document. The nib-loading code instantiates the objects, configures them, and reestablishes any inter-object connections that you created in Interface Builder.”

Contents of a Nib file:

Interface objects: These are the user interface elements in the application – views, windows, buttons, tables etc. Interface objects can also represent non-visual objects like controller objects that your application uses to manage the visual objects.

File’s Owner: This is a proxy object and represents the object that you will create in code and pass to the the Nib loading code. If your Nib file and the class of your object have the same name then simply calling alloc and init for your object will automatically load the correct Nib file. For example, consider the following files:

MyTableViewController.m

MyTableViewController.h

MyTableViewController.xib

Here, I assume MyTableViewController.{h,m} is a class derived from UITableViewController (or NSTableViewController). When an object of this type is created by calling


MyTableViewController *mtvc = [[MyTableViewController alloc] init];

Automatically, the object is associated with the nib file named MyTableViewController.xib and the corresponding elements from the nib file are loaded and the outlets in the object are hooked up.

This behavior can be changed in the following way – open the nib file in interface builder. Select “File’s Owner” object and in the identity inspector, set the class to any class in your code.

First Responder: This is also a proxy object and represents the first object in the application’s dynamic responder chain. For more information about the responder chain and how it is used to dispatch events in AppKit–based applications, see Event Architecture in Cocoa Event-Handling Guide. For information about the responder chains and handling actions in iPhone applications, see Event Handling Guide for iOS.

Note: Only a very simple application should store all its user interface components in a single nib file. It is better to distribute components across multiple nib files. Creating smaller nib files allows you to load only required portions of the interface.

Memory management and Nib file objects:

Each time a nib file is loaded the underlying code creates a NEW copy of the objects in the file. This means that your code is responsible for releasing the objects when it is done. How this needs to be done varies depending on the platform and memory model:

Mac OS X managed memory model: Top level objects in the nib file have a positive retain count. Objects that have parents are retained by their respective parents and do not have additional retain counts. Your code is responsible only for releasing the top level objects.

Mac OS X garbage collected memory model: Objects in the graph are kept in memory through strong memory references. But top level objects do not have strong references. Your code is responsible to create the strong reference to top level objects to prevent the object graph from being released.

iOS managed memory model: Objects are retained either using a setter method (setValue:forKey:0 or by default (if no setter is available). Objects in the graph that are not at the top level are retained by their parents (created autoreleased so they will have retain counts equal to the number of parents). Any objects that are hooked up to your class using IBOutlets will have additional retain counts. Your code is responsible for releasing all top level objects as well as all outlets.

Important note:
There is a difference in Mac OS X and iOS managed memory models. In the former, all objects are retained and they are connected via the object graph to the top level objects. So sending release to the top level objects will “propagate” the release to the other objects in the graph. In iOS, in addition to top level objects all IBOutlets have to also be released.

Good programming conventions:
Always have outlets for your top level objects and define setter methods to retain and release them. Remember to release all your outlets in -dealloc as well as -viewDidUnload. Doing this will make your code portable across platforms. Example:

@interface MyController: UIViewController {
        IBOutlet UITextField *textField;
}

@property(retain) IBOutlet UITextField *textField;
@end

@implementation MyController
@synthesize textField;

-(void) viewDidUnload {
        self.textField = nil;
}

-(void) dealloc {
        self.textField = nil;
        [super dealloc];
}
@end

This will ensure that IBOutlets are always retained in both iOS and Mac OS X (managed memory model) platforms. Your code will have to release the outlets in -viewDidUnload (iOS only) as well as -dealloc. Note that setting the textField ivar to nil will release it (the setter method will release the ivar before setting the new value) and also set it to nil.

The above implementation leaves IBOutlets exposed to “tampering”. So someone else using your code could in theory access your outlets and mess with them (say displaying something in the text field). You can get some protection against that using the implementation below where the @property is moved to the implementation file.

MyController.h

@interface MyController: UIViewController {
        IBOutlet UITextField *textField;
}

@end

MyController.m

@interface MyController()
@property(retain) IBOutlet UITextField *textField;
@end

@implementation MyController
@synthesize textField;

-(void) viewDidUnload {
        self.textField = nil;
}

-(void) dealloc {
        self.textField = nil;
        [super dealloc];
}

@end

Since code distributions (library, frameworks etc) usually include only a compiled binary along with header files the @property will be hidden from other users of your code. But remember that there is nothing “private” about methods in objective-c. If a MyController object (with class defined like above) gets a -setTextField: or -textField message it will respond and do the right thing. The only “private” part is that without access to MyController.m one would not know the setter exists!!

Another (popularly called out) nit in the above code is about calling an instance method from -dealloc (i.e. the setter). Usually it is not a good practice to call instance methods from -dealloc because within this method the state of your object is undefined. There are no guarantees that the instance method can behave correctly. So the usual preferred way to implement -dealloc is

-(void)dealloc {
        [textField release];
        [super dealloc];
}

While it is usually good practice not to call instance methods from -dealloc in this instance I believe it is safe unless someone inherits from MyController and decides to override -setTextField: to do something funky!! But sometimes it is tempting to avoid this convention for the following convenience (put in big scary note in .h file warning against overriding setters):

MyController.m

@interface MyController()
@property(retain) IBOutlet UITextField *textField;
@end

@implementation MyController
@synthesize textField;

-(void) releaseOutlets {
self.textField = nil;
}

-(void) viewDidUnload {
        [self releaseOutlets];
}

-(void) dealloc {
[self releaseOutlets];
        [super dealloc];
}

@end

In iOS, each time you add an IBOutlet you have to make sure you remember to release it in two methods. Easier to do the above and save some trouble.

Reference:

Fixing CoreData Error in the iPhone Simulator

While developing a CoreData based application if you change your data model and try to rerun you get the following error:
“The model used to open the store is incompatible with the one used to create the store”

The error occurs because the application (in the simulator) still has the old CoreData database while the ModelObjectContext in your application is referring to your new CoreData.

The only way to fix this is problem is to delete the application from the simulator.

Everything you need to know about pointers in C

Everything you need to know about pointers in C

Tags:

Smart Pointers in C++

There are a number of “smart pointer” implementations in C++. Each one has a different set of features and it seems hard to pick one that satisfies scenarios.

auto_ptr: Available as part of the standard C++ library (#include ). Has the several useful features and shortcomings:

  1. Pointer initializes itself to 0 if not explicitly initialized
  2. Pointer automatically deletes itself when it goes out of scope
  3. Only one auto_ptr can point to an object at a given time (so no question of reference counting). If you do x=y auto_ptr x will now point to what was pointed to by y. But y will now point to NULL!!
  4. Does not work for arrays because it deletes its pointer with delete and not delete []
  5. Does not work with STL. Warning: May appear to work but reportedly results in subtle devastating bugs
  6. It is not thread safe

Feature 3 limits its usefulness IMHO. This article – Using auto_ptr Effectively – summarizes auto_ptr features.

shared_ptr: This pointer from  the BOOST C++ library uses reference counting. So a shared_ptr that is assigned to another will point at the same object in memory and will increment a reference count to that object. When either of the pointers is deleted the object reference count is decremented. If the object reference count is zero the object is truely deleted from memory.

  1. Reference counted
  2. Does NOT do copy on write. If shared_ptr x is assigned to y and later *x (or *y) is changed then the memory location pointed to is changed (just like a regular pointer)
  3. Cycling references may lead to memory leaks – this is a problem with reference counting itself and not this specific implementation
  4. Thread safety – some operations seem atomic. See BOOST docs.
  5. Cannot hold a pointer to an array (see shared_array)
  6. Pointer automatically deletes itself (or reduces reference count) when it goes out of scope

This may be already added to C++ standard library in the near future (already in?).

Const in C++

Const declaration:

const int* x; //constant data (*x); non-constant pointer
int const *x; //same as above
int * const x; //constant pointer; non-constant data
const int * const x; //const data; const pointer

Const member functions:
Function values can be declared const. Helps specifically in operator overloading.

const Foo operator*(const Foo& lhs, const Foo& rhs);

Foo a,b,c; 

a = b*c; //legal
(a*b) = c; //This will work if return value is not const

It is not useful to assign any value to the product of two variables but it can happen accidentally. Example, using = instead of ==

if(a*b = c) {
}

Const member functions in a class cannot modify the contents of the class. They make it possible to work with const objects. Member functions differing only in their “constness” can be overloaded.

class Foo {
public:
    const int& value() const;
       int& value();

private:
    int x;
};

main() {
    Foo x(1);
    cout<<x.value(); //Non-const function is called

    const Foo y(2);
    cout<<y.value(); //const function is called
}

Bitwise Constness:
C++ gives only bitwise constness. This means const member functions cannot modify pointers in a class. But they can modify the data the pointer points to.

Mutable:
Mutable type modifier allows variables to be modified even by const functions.

Class Foo {
public:
    void test() const; //can modify x but nor y
private:
    mutable int x;
    int y;
};

Tags: , ,

Misc C++ links

C++ file I/O quick notes.

Gcc and uninitialized variables

Gcc will not produce any warnings about uninitialized variables if the optimization level is not 1 or greater. The following code has an obvious uninitialized variable problem.

test.c

int foo() {
    int x;
    return x;
}

But gcc (3.4 and 4.2.1) produces no warning or error when you use this command line:

gcc -Wall -Werror -O0 test.c
gcc -Wall -Werror  test.c (this defaults to -O0)

I have tested the above on Linux as well as Mac OS X.
The -Wall flag is supposed to automatically include the -Wuninitialized flag. But if the optimization level is 0 then the check for uinitialized variables is not done.

gcc -Wall -Werror -Wuninitialized test.c

If included explicitly like above:

$ gcc -Wall -Werror -Wuninitialized test.c
cc1: warnings being treated as errors
cc1: warning: -Wuninitialized is not supported without -O

For gcc to check for uninitialized variables you need to throw at least -O1 optimization.

From the gcc man page:

-Wuninitialized
Warn if an automatic variable is used without first being
initialized or if a variable may be clobbered by a “setjmp” call.

These warnings are possible only in optimizing compilation, because
they require data flow information that is computed only when
optimizing. If you do not specify -O, you will not get these
warnings. Instead, GCC will issue a warning about -Wuninitialized
requiring -O.

However, uninitialized checking does not seem to work correctly. This code compiles on Mac OS X (Snow Leopard):

#include <stdlib.h>
#include <iostream>

int main() {

    int l_retVal;
    unsigned int x = 1;
    unsigned int y = random() % 10;
    if(y == x) {
        l_retVal = 2;
        std::cout<<"HERE \n";
    }
    return l_retVal;
}

$ g++ -Wall -Werror -Wuninitialized -O test.cpp
$

CPU, Graphics, Stream computing, and OpenCL

  • NVIDIA GPU Gems1 book online
  • NVIDIA GPU Gems2 book (discusses GPU architecture) online

OpenCL Links

Command line parsing in C++ – Tclap

TCLAP library

Precision in games

Why not to use double precision to represent objects in 3D – TomF’s Tech Blog