Reserved keywords in Objective-C

Sometimes you’ll be happily coding a way and then something seems a bit awry.

E.g. I suddenly found I couldn’t connect an IBAction from a View to a Controller. It turned out it was because I was using a reserved keyword, register:

In hindsight pretty obvious but puzzling at the time as I wasn’t getting an error.

Words You Can’t Use
auto
break
case
char
const
continue
default
do
double
else
enum
extern
float
for
goto
if
inline
int
long
register
restrict
return
short
signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
while
_Bool
_Complex
_Imaginery

Words You Shouldn’t Use
BOOL
Class
bycopy
byref
id
IMP
in
inout
nil
NO
NULL
oneway
out
Protocol
SEL
self
super
YES
@interface
@end
@implementation
@protocol
@class
@public
@protected
@private
@property
@try
@throw
@catch()
@finally
@synthesize
@dynamic
@selector
atomic
nonatomic
retain

http://cupsofcocoa.com/2010/09/09/reserved-keywords/

Templates for @interface and @implementation files

I’m always checking where I have to put my instance variables and whether I need braces so I just created a simple template that I use to check when necessary.

Interface Template

Implementation Template

More here:
http://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163-CH12-TPXREF126
and a post re private instance variables in the .m file here:
http://stackoverflow.com/questions/10407848/is-this-a-new-way-to-define-private-instance-variables-in-objective-c

viewDidUnload and dealloc methods with ARC

In a nutshell:

1. you should rarely need a dealloc method. You do not have to (and indeed can’t) release instance variables

2. and viewDidUnload is deprecated

From “Transitioning to ARC Release Notes”

http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

“Custom dealloc methods in ARC do not require a call to [super dealloc] (it actually results in a compiler error). The chaining to super is automated and enforced by the compiler.

You create objects using alloc; the runtime takes care of deallocating objects.”

See also:

http://stackoverflow.com/questions/7292119/custom-dealloc-using-arc-objective-c

and

http://stackoverflow.com/questions/12630611/are-dealloc-and-viewdidunload-methods-still-required-when-using-arc-pre-ios

Convert to Modern Objective-C Syntax

I thought I’d give this a roll. So, in Xcode I ran it from Edit > Refactor.

Pleasantly surprised at how straightforwards it was.

Quick reminder:

Arrays:

Dictionaries:

Numbers:

The only problems that seem to need looking out for are:

1. relying on early nil termination of arguments when creating an array

2. the need to box BOOL values

http://jamesdempsey.net/2012/07/30/moving-to-new-objective-c-literals/

Convert a project to ARC

Recently had to convert a gnarly old project to ARC. Here’s how I got on:

1. first, created a git branch

2. Xcode > Edit > Refactor > Convert to Objective-C ARC

and got “Cannot Convert” with 51 issues!

Back to the drawing board.

3. Read this:

http://stackoverflow.com/questions/9018366/how-to-enable-disable-arc-in-an-xcode-project

and

http://www.learn-cocos2d.com/2011/11/everything-know-about-arc/

Summarising this last page which has tons of information:

i. use >= iOS5.0

ii. use LLVM 3.0 or greater (currently 4.2) – note, if you’re Converting then this will be taken care of

iii. build 3rd party libraries separately as a static library or, less appealing, disable ARC for individual files with -fno-objc-arc (see later)

Here’s what i did:

a. Make sure I was only Converting my main Target

b. I was using ShareKit which was generating loads of issues. But I was using it in a pretty minor way so removed it and added a comment to come back to it

c. An old file I was using for reference had issues. I removed it from Build Phases > Compile Sources

d. Remove my lines of code that used retain, retainCountrelease, autorelease

e. Added -fno-objc-arc for 3rd party files that used retain, retainCountrelease, autorelease – and, in the headers of these files, added //TODO – update this file for ARC

Note: to disable ARC on multiple files, select all your files, press Enter, type in -fno-objc-arc and then click off the pop up once done.

Guide: http://stackoverflow.com/questions/6646052/how-can-i-disable-arc-for-a-single-file-in-a-project

f. Ran Xcode > Edit > Refactor > Convert to Objective-C ARC

Note that you need to make sure you’ve deselected files from the Target you want to keep ARC free.

Why?

‘cos “Convert to Objective-C ARC” is a code rewriting tool whereas -fno-objc-arc is a compile time flag. It’s irrelevant for the purpose of refactoring.

See this post:

http://stackoverflow.com/a/15029714/343204

g. A final obstacle – I was using Crashlytics which runs a Build Phase script. Select “Run script only when installing” to disable.

And finally, I got to this:

Screen Shot 2013-04-11 at 11 Apr  13.13.06http://www.snowcrash.eu/wp-content/uploads/2013/04/Screen-Shot-2013-04-11-at-11-Apr-13.13.06-588x397.png 588w, http://www.snowcrash.eu/wp-content/uploads/2013/04/Screen-Shot-2013-04-11-at-11-Apr-13.13.06.png 727w" sizes="(max-width: 300px) 100vw, 300px" />

So, I created a final git branch – just so I could roll back and clicked Next.

Now, the code was converted. But it wouldn’t build complaining about:

Undefined symbols for architecture i386:
“_OBJC_CLASS_$_MyOldViewController”, referenced from:
objc-class-ref in ANewViewController.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)

What was happening here was I had removed the file (MyOldViewController) from Targets > Build Phases > Compile Sources BUT still had the file included and referenced in ANewViewController.

More here:

http://stackoverflow.com/questions/6984368/undefined-symbols-for-architecture-i386-objc-class-skpsmtpmessage-refere

I just needed to remove it from these files.
And bingo, it built and ran!

Note, here’s a review of some of the changes that were made:

1. retain was replaced with strong

2. Where I had an NSAutoReleasePool, the relevant bit of code was wrapped with @autoreleasepool {}

3. references to retain, release, autorelease were removed

4. calls to super’s dealloc were removed. Note, dealloc methods themselves aren’t removed but in most cases can be removed. See the separate post on dealloc methods in ARC.

5. where I had references to my Delegate, an  __unsafe_unretained modifier was added

6. where I was casting to an NSString after using functions like CFURLCreateStringByAddingPercentEscapes, it added CFBridgingRelease

When to use self.myInstanceVariable and when to use _myInstanceVariable

Here’s a question I’ve had a few times so here are some simple rules. But, first a quick explanation.

self.myTitle means you’re accessing an instance variable that has been created using an @property such as:

@property (nonatomic, copy) NSString *myTitle;

Unless you’re doing something special (see an earlier post) what @property does is create getters / setters and an instance variable. Xcode prefixes the instance variable with an underscore.

Note that if you needed this to be differently named you would need to use @synthesize to manually set it however, you need a very good reason. By auto-generating instance variables with a leading underscore (now the convention for instance variable naming), Xcode makes @synthesize unnecessary.

So, if you don’t have any requirements for getters/setters (and have therefore not used @property) then you don’t have the option of using self.myTitle. You would simply access it using:

myTitle = @”some title”;

Typically you would do this when you just want to create a local variable.

However, if you are using an @property then you would access this instance variable using getters:

someLabel.text = self.myTitle;

If you had to access the instance variable directly then you would use the underscore prefix to access it:

someLabel.text = _myTitle;

However, you need to have a good reason to use an instance variable this way. An example would be in a dealloc method when you don’t know the state of your object and so getters/setters would work in unknown ways. However, with the introduction of ARC much of the code in books and on the internet with the dealloc method becomes defunct.

More info here:

http://useyourloaf.com/blog/2011/02/08/understanding-your-objective-c-self.html

and here:

http://stackoverflow.com/questions/822487/how-does-an-underscore-in-front-of-a-variable-in-a-cocoa-objective-c-class-work

 

Objective-C ARC: strong vs retain and weak vs assign

strong is the same as retain in a property declaration so for ARC projects use strong instead of retain.

Use assign for C primitive properties and weak for weak references to Objective-C objects.

http://stackoverflow.com/questions/8927727/objective-c-arc-strong-vs-retain-and-weak-vs-assign

and more here: http://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html

However, note that assign is the default. So, for an int you would use:

@property (nonatomic) int value; // assign by default

http://stackoverflow.com/questions/7827237/what-are-the-default-attributes-for-objective-c-properties/7827261#7827261

Objective-C: retain vs copy

Short answer: if you’re using an NSString you should be using copy.

http://stackoverflow.com/a/387984/343204

 

Long answer

Copy makes a copy of a variable.

Retain shifts the pointer when set to a new variable. i.e. it becomes the new variable.

Here’s an example that clarifies whether to use retain or copy:

NSMutableString *someName = [NSMutableString stringWithString:@”Dougal”];

Person *p = [[[Person alloc] init] autorelease];
p.name = someName;

[someName setString:@”Zebedee”];

If p is declared using copy then it’s set to Dougal on line 3 and, on completion, still has that value.

However, if p is declared using retain then it’s set to someName. So, when someName is set to “Zebedee”, p is also set to “Zebedee”.

More on this here: http://stackoverflow.com/questions/387959/nsstring-property-copy-or-retain

And if you want to get into the details of implementing NSCopying or NSCopyObject then you should look at Rob Napier’s post: http://robnapier.net/blog/implementing-nscopying-439