I've got a theory, and it's this: Steve Jobs believes he's gambling Apple's future — the future of a corporation with a market cap well over US $200Bn — on an all-or-nothing push into a new market. HP have woken up and smelled the forest fire, two or three years late; Microsoft are mired in a tar pit, unable to grasp that the inferno heading towards them is going to burn down the entire ecosystem in which they exist. There is the smell of panic in the air, and here's why ...An interesting read which has almost nothing to do with the current Jobs vs. Flash smackdown.
Friday, April 30, 2010
The real reason why Steve Jobs hates Flash
In an interesting but somewhat mis-titled blog post, Charles Stross pulls together current trends and looks five years into the future in order to explain the motivation behind Apple, HP and others today:
Thursday, April 29, 2010
Thoughts on Flash, by Steve Jobs
Apple CEO Steve Jobs has published a letter entitled "Thoughts on Flash" on Apple's site today. If you've been following the "no flash on iPhone/iPad" controversy, you'll recognize all the arguments that Jobs lines up. Never a fan of Flash myself, I tend to see Apple's side of things and I think Jobs shows that Apple really has a compelling reasons to keep Flash off of the iPhone/iPad platform.
It's interesting to see Jobs openly state the "most important reason" for prohibiting Flash:
I think part of the controversy is due to how good the iPhone and iPad actually are. Most users are blissfully unaware of how limited the CPU and RAM on their iPhone are. Apple has delivered a user experience that rivals (and with iPad even exceeds) that of a fully powered PC or Mac system.
High level layers like Flash are woefully inefficient. Simple calculations in Flash can be a hundred or even a thousand times slower than in a lower level language like Objective-C. There's so much processing power available in a modern desktop or laptop machine that this inefficiency is rarely noticed. It's a much different story for your iPhone however.
Flash developers seem particularly tone deaf to performance issues. I think we've all seen web-based Flash apps that take forever to download, often showing you some annoyingly wizzy progress meter while you stare at a blank screen for two minutes. Of course, for the Flash developer loading it directly on his development machine, it appears in seconds. Now imagine this experience on your iPhone.
It's interesting to see Jobs openly state the "most important reason" for prohibiting Flash:
We know from painful experience that letting a third party layer of software come between the platform and the developer ultimately results in sub-standard apps and hinders the enhancement and progress of the platform.This directly echoes what John Gruber wrote earlier this month in "Why Apple Changed Section 3.3.1". As a developer, I really understand this. And I'm not gloating because I took the time to learn Objective-C and Cocoa Touch. I've worked in enough languages, frameworks and platforms over the years to know that it's critical to understand a platform at its base level, even if you do most of your work in a higher level language or framework.
I think part of the controversy is due to how good the iPhone and iPad actually are. Most users are blissfully unaware of how limited the CPU and RAM on their iPhone are. Apple has delivered a user experience that rivals (and with iPad even exceeds) that of a fully powered PC or Mac system.
High level layers like Flash are woefully inefficient. Simple calculations in Flash can be a hundred or even a thousand times slower than in a lower level language like Objective-C. There's so much processing power available in a modern desktop or laptop machine that this inefficiency is rarely noticed. It's a much different story for your iPhone however.
Flash developers seem particularly tone deaf to performance issues. I think we've all seen web-based Flash apps that take forever to download, often showing you some annoyingly wizzy progress meter while you stare at a blank screen for two minutes. Of course, for the Flash developer loading it directly on his development machine, it appears in seconds. Now imagine this experience on your iPhone.
Wednesday, April 28, 2010
Understanding iPad wallpaper image size
Most Fridays since we started the Able Pear blog (over two years now), we have shared a set of iPhone wallpapers: 320x480 portrait images that also work on the iPod touch and the Palm Pré. We love doing this and call it iPhone Fridays.
The Friday before Apple's iPad launch, we started producing iPad wallpapers in parallel with the iPhone wallpapers using the same images but at a much higher resolution: 768x1024, the resolution of the iPad screen. Up until then we did not have an iPad to view them on. The next day we all picked up our iPads. The images were beautiful but there was one exception I had not anticipated even though I've seen it in over and over in the media hype; the iPad can be in any orientation.
The images that we had created were nice but when you rotated the iPad from portrait (tall) to landscape (wide) the image was scaled up 133% to fill the width of the device.
Later that week I created a PNG file in Illustrator to load on my iPad to visualize how the device was presenting the image in the background. I knew that the highest resolution was 1024 pixels and the smallest was 768 pixels and that I would have to create an image that was 1024x1024 so that I would fill the iPad's screen in any orientation without scaling the image.
We can also see that the "always" viewable image area is 768x768 in the center of the 1024x1024 image. The upper and lower parts of the image are presented in portrait and the left and right are seen when in landscape, but the image itself is not scaling the fit the screen.
So this is my conclusion: iPad wallpapers need to be 1024x1024 to accommodate both orientations. Okay, that's a given, but now I'm left with a new question: What's up with the corners and if they are never presented then should you omit the image data from the wallpaper to save on file size? After all, adding the corners up, that's 128 pixels by 128 pixels, times four.
What are your thoughts? Keep the image data intact or delete the corners and save it as a 24-bit PNG? If you're making iPad wallpapers, will you use 1024x768 or will you adopt the larger square format? If you are an iPad owner what would you rather download? Let us know and we'll see you on iPhone Friday. Cheers!
The Friday before Apple's iPad launch, we started producing iPad wallpapers in parallel with the iPhone wallpapers using the same images but at a much higher resolution: 768x1024, the resolution of the iPad screen. Up until then we did not have an iPad to view them on. The next day we all picked up our iPads. The images were beautiful but there was one exception I had not anticipated even though I've seen it in over and over in the media hype; the iPad can be in any orientation.
The images that we had created were nice but when you rotated the iPad from portrait (tall) to landscape (wide) the image was scaled up 133% to fill the width of the device.
Later that week I created a PNG file in Illustrator to load on my iPad to visualize how the device was presenting the image in the background. I knew that the highest resolution was 1024 pixels and the smallest was 768 pixels and that I would have to create an image that was 1024x1024 so that I would fill the iPad's screen in any orientation without scaling the image.
We can also see that the "always" viewable image area is 768x768 in the center of the 1024x1024 image. The upper and lower parts of the image are presented in portrait and the left and right are seen when in landscape, but the image itself is not scaling the fit the screen.
So this is my conclusion: iPad wallpapers need to be 1024x1024 to accommodate both orientations. Okay, that's a given, but now I'm left with a new question: What's up with the corners and if they are never presented then should you omit the image data from the wallpaper to save on file size? After all, adding the corners up, that's 128 pixels by 128 pixels, times four.
What are your thoughts? Keep the image data intact or delete the corners and save it as a 24-bit PNG? If you're making iPad wallpapers, will you use 1024x768 or will you adopt the larger square format? If you are an iPad owner what would you rather download? Let us know and we'll see you on iPhone Friday. Cheers!
Tuesday, April 27, 2010
Objective-C Tuesdays: @property and @synthesize
See Also
Variables in Objective-C
Last time we looked at writing getters and setters for Objective-C classes. Today we'll look at generating them automatically using the Variables in Objective-C
@property
and @synthesize
directives.Before Objective-C 2.0 was introduced, if you wanted to add getters and setters to a class, you wrote them yourself using instance methods, which caused some classes to become heavy with boilerplate code:
// example of hand-written getters and setters @interface Person : NSObject { int age; Address *address; NSString *name; } - (int)age; - (void)setAge:(int)anAge; - (Address *)address; - (void)setAddress:(Address *)anAddress; - (NSString *)name; - (void)setName:(NSString *)aName; // ... @end @implementation Person - (int)age { return age; } // assign-type setter - (void)setAge:(int)anAge { age = anAge; } - (Address *)address { return address; } // retain-type setter - (void)setAddress:(Address *)anAddress { if (address != anAddress) { [address release]; address = [anAddress retain]; } } - (NSString *)name { return name; } // copy-type setter - (void)setName:(NSString *)aName { if (name != aName) { [name release]; name = [aName copy]; } } // ... @endThis is a lot of code to write, and the
Person
class barely does anything yet. The @property
directive will remove some of the boilerplate code from the @interface
section of the class and the @synthesize
directive will clean up the @implementation
Declaring properties
A getter and setter form a logical property of a class. Properties typically correspond directly to instance variables, but don't have to. Sometimes a property is calculated on the fly, or the name of the instance variable is different than the name of the property. The
@property
directive replaces the getter and setter method declarations in the @interface
of the class. // declaring age property @interface Person : NSObject { int age; Address *address; NSString *name; } @property int age; // ... @endNotice that the property declaration looks a lot like an instance variable declaration. At a high level, a property is very similar to an instance variable. But as far as the compiler cares, a
@property
is simply a replacement for declaring the getter and setter methods:@property int age;is just a substitute for
- (int)age; - (void)setAge:(int)anAge;If you don't write the corresponding getter and setter methods in the
@implementation
section, you'll see compiler warnings like this:property 'age' requires method '-age' to be defined - use @synthesize, @dynamic or provide a method implementation property 'age' requires the method 'setAge:' to be defined - use @synthesize, @dynamic or provide a method implementation
Read-only properties
Sometimes, you want properties to be read-only. For example, we might store the person's birthdate instead of age:
// age property calculated on the fly @interface Person : NSObject { NSDate *birthDate; Address *address; NSString *name; } @property int age; // ... @end @implementation Person - (int)age { NSCalendar *calendar = [NSCalendar currentCalendar]; NSDate *today = [NSDate date]; NSDateComponents *components = [calendar components:NSYearCalendarUnit fromDate:birthDate toDate:today options:0]; return components.year; } // ... @endYet it doesn't make sense to write the corresponding
setAge:
method here. If we compile this code, we'll still get nagged about the setter:property 'age' requires the method 'setAge:' to be defined - use @synthesize, @dynamic or provide a method implementationTo silence this, we need to add an attribute to the property. Property attributes go in parentheses after the
@property
keyword but before the type and name:@property (readonly) int age;Here we've told the compiler that the
age
property is readonly
, so not to worry about the setter. By default, properties are readwrite
. You can label them with the readwrite
attribute, but since it's the default, it's redundant and you'll rarely see it.Object properties
Let's set aside the calculated
age
property and go with our plain old int
version. The next property of the Person
class is address
:// declaring address property @interface Person : NSObject { int age; Address *address; NSString *name; } @property int age; @property Address *address; // ... @endWhen you compile this, you'll see warnings like:
no 'assign', 'retain', or 'copy' attribute is specified - 'assign' is assumed assign attribute (default) not appropriate for non-gc object property 'address'The compiler has noticed that
address
is an Objective-C object type and is reminding you to do the appropriate memory management. (Those lucky Mac developers don't have to worry about this any more since they now have garbage collection.) In addition to readwrite
/readonly
there's another set of property attributes: assign
, retain
and copy
. Since address
uses retain memory management, we'll change it to look like@property (retain) Address *address;At this stage,
assign
, retain
and copy
are simply documentation to other programmers about the memory management strategy for the property. If you write the setter yourself, the compiler isn't smart enough to tell if you actually wrote the correct type of setter, so be careful! There's nothing worse than code that says it's doing one thing and actually does another. So what's the point? We'll see when we get to @synthesize
.Finishing up the properties for our class, we declare a property for
name
that uses a copy memory management scheme. (Last week's post explained why we use copy
for NSString
properties.)// declaring name property @interface Person : NSObject { int age; Address *address; NSString *name; } @property int age; @property (retain) Address *address; @property (copy) NSString *name; // ... @end
Plain old pointer properties
Most Objective-C code uses objects instead of plain old C
struct
s, strings and arrays, but sometimes you'll need to use them, often when working with low level C libraries. You might be tempted to document your memory management for these plain old pointers as you would Objective-C objects:// ERROR: won't compile @interface Person : NSObject { int age; Address *address; NSString *name; char const *username; // plain old C string } @property int age; @property (retain) Address *address; @property (copy) NSString *name; @property (copy) char const *username; // plain old C string // ... @endUnfortunately, since plain old C types don't have
retain
/release
memory management like Objective-C objects, this muddies the meaning of copy
and the compiler will stop with an error like:property 'username' with 'copy' attribute must be of object typeUnfortunately, marking a property like this
assign
when your setter actually makes a copy doesn't seem right either:// not quite right @property (assign) char const *username;My advice is to leave off
assign
, retain
and copy
from properties for plain old C pointers and use a comment to note your memory management strategy.I'm out of time right now, so I'll have to finish this up next week. Coming up, the
nonatomic
property attribute, and the @synthesize
directive.
Friday, April 23, 2010
iPad Friday: April 23, 2010
Hello and happy Friday to you all. Today we are continuing with the Images of Spring collection iPad wallpapers. The full-size iPad wallpapers are 1024 x 1024 so that you'll have the best resolution in both portrait and landscape orientations. Enjoy.
(click on image for full-size wallpaper)
(click on image for full-size wallpaper)
Wednesday, April 21, 2010
Android 2010 is Windows 1990
In an article titled Three Android lessons learned the hard way, Jonathan Blum talks about his experiences deploying Android phones in his business. It's a typical journal of a user working with a nascent technology, something we've all seen and done before in various incarnations. But one passage struck me as all too familiar:
Is this where Android is headed? Are we going to have sysadmins for our business phones? Is IT going to lock them down to keep us monkeys from installing too many apps? Really?
Plan on carefully testing apps on your businesses phones before unleashing them on your entire operation. Trust me, nothing is more frustrating than not being able to answer a client's call because ESPN Mobile is installed.If you've ever worked in any large enterprise with a full time IT staff, you're familiar with IT testing new versions of Windows before rolling out a company-wide upgrade, or qualifying a new application before deploying it to users' computers. In most big companies, there's no "personal" in PC anymore.
Is this where Android is headed? Are we going to have sysadmins for our business phones? Is IT going to lock them down to keep us monkeys from installing too many apps? Really?
Tuesday, April 20, 2010
Objective-C Tuesdays: instance variables, getters and setters
See Also
Variables in Objective-C
Last time we looked at instance variables of Objective-C classes. Today we're going to look at writing getters and setters for instance variables.Variables in Objective-C
As we saw, instance variables have protected scope by default, which makes them visible in instance methods of the class that defines them and all subclasses, but hidden to all other code and classes by default. Hiding the inner workings of a class is a principal of object oriented programming known as encapsulation. In general, it's better to tell your objects what to do rather than ask them for their data. But there are times when you need to get and set an object's data directly, particularly for objects that correspond to those things your application and users directly manipulate, like address book contacts or cookie recipes. The typical way to do this is to write getter and setter methods. Before Objective-C 2.0, these were always written by hand, and there are still times when you would want to write your own rather have the compiler generate them for you using the
@property
and @synthesize
directives.Getters
A conventional getter method in Objective-C has the same name as the instance variable:
// getter method example @interface CookieRecipe : NSObject { NSString *name; // instance variable name } - (NSString *)name; // getter method for name ivar @end @implementation CookieRecipe - (NSString *)name { // getter method for name ivar return name; } @endThis works because instance variables and instance methods live in separate namespaces. The compiler can always figure out whether you're calling a method or accessing an instance variable, so there's never a problem. Getter methods are generally very simple and rarely have side effects.
Compiler generated getters are as simple as the example above. There are two common cases where you might want to write them by hand: calculated properties and defensive copying.
Sometimes a class has a property that's easily calculated from other properties, such as a
fullName
property that can be created on the fly by joining firstName
and lastName
, or a yearsWithCompany
property that's calculated by subtracting hireDate
from today's date. These types of properties are usually read only and quick to calculate.Defensive copying is done when your object has some mutable internal data that it needs to share with other code, but which other code should not change. For example, you might have a
User
class that has an NSMutableArray
containing the user's friends
:// example of exposing mutable internals @interface User : NSObject { NSMutableArray *friends; // contains other Users } - (NSMutableArray *)friends; @end @implementation User - (NSMutableArray *)friends { return friends; } @endThe
friends
getter returns the friends
instance variable directly. This might work out okay if all the code that uses friends
is polite and only reads the list of friends. But it's all to easy to innocently do something like this:// accidentally changing internal state NSMutableArray *boneheads = [user friends]; // boneheads now points to same mutable array that // the friends instance variable does NSPredicate *boneheadsOnly = [NSPredicate predicateWithFormat:@"species == 'Minbari'"]; [boneheads filterUsingPredicate: boneheadsOnly]; // oops! all the user's non-Minbari friends are gone // -filterUsingPredicate: removes items that don't matchMutable objects like
NSMutableArray
naturally have methods like -filterUsingPredicate:
that change the data they contain. By sharing a mutable instance variable directly, the User
class allows other code to intentionally or unintentionally muck around with its internal state, breaking encapsulation. While bugs caused by unintentional mucking aren't usually too hard to track down, it's the intentional mucking that causes more trouble in the long run. By exposing its internals like this, the User
class allows itself to become closely coupled with the code that calls it, since callers can add or remove items directly to or from the friends
collection. The rules for adding and removing friends get spread around the app in numerous locations rather than centralized in User
, making the system harder to understand, harder to change; small changes in User
then affect more of the code than necessary.So rather than return a mutable internal value directly, there are a couple of options in Objective-C. When you're using a class like
NSMutableArray
that has an immutable superclass, you can upcast the returned instance variable to the immutable superclass:// getter that upcasts to immutable superclass @interface User : NSObject { NSMutableArray *friends; // instance variable is mutable } - (NSArray *)friends; @end @implementation User // return type of getter is immutable - (NSArray *)friends { return friends; } @endIt's called upcasting since it casts a subclass reference "up" to a superclass reference. Because this is always a safe cast, Objective-C will do this automatically for you with no explicit cast is needed. While this won't prevent a malicious programmer from downcasting the result back to its mutable type and mucking around, in practice this works pretty well (and if you have a malicious programmer on your team, you have a bigger problem than a little code can solve).
Sometimes the instance variable you want to share doesn't have an immutable superclass, or most callers of the getter need to filter or manipulate the returned value. In that case, you can do an actual defensive copy:
// getter that does a defensive copy @interface User : NSObject { NSMutableArray *friends; // instance variable is mutable } - (NSMutableArray *)friends; @end @implementation User // return type of getter is mutable - (NSMutableArray *)friends { // return an autoreleased copy return [[friends mutableCopy] autorelease]; } @endNow the caller can delete your friends all they want. You can use whichever creation or copy method is appropriate for the mutable data; just make sure to properly
autorelease
the return value.Setters
The Objective-C convention for setter names is similar to Java's: capitalize the instance variable name and prefix with
set
. Setters come in different varieties, depending on the type of instance variable. The simplest kind is used for primitive types like int
s and object references that aren't retained, like delegates.// assignment setter - (void)setAge:(int)anAge { age = anAge; }Assignment setters are trivial, but the fun starts when you have to deal with memory management and retain counts. Here's an example of a setter that retains the new value and releases the old one, but it has a subtle bug:
// retain setter WITH BUG - (void)setAddress:(Address *)theAddress { [address release]; // release old address address = [theAddress retain]; // retain new address }This setter might never give you a problem, if you're lucky. But what happens if the new address and old address are the same object? What happens when that object's retain count is 1?
// retain setter WITH BUG // suppose address == theAddress // and retain count is 1 - (void)setAddress:(Address *)theAddress { // retain count is 1 [address release]; // retain count now 0, // dealloc called address = [theAddress retain]; // oops! theAddress points at // invalid memory }There are two common ways to write a setter to get around this. The first way is to check for self-assignment:
// retain setter with self-assignment check - (void)setAddress:(Address *)theAddress { if (theAddress != address) { [address release]; // release old address address = [theAddress retain]; // retain new address } }The second way is to retain first and release last:
// retain setter that retains first - (void)setAddress:(Address *)theAddress { [theAddress retain]; // retain new address [address release]; // release old address address = theAddress; }This will prevent the retain count from going to zero in the case of self-assignment.
Just as you may want to defensively copy in a getter, you may want to do the same in a setter. Here's an example a malicious programmer would love:
// be careful with that setter @interface User : NSObject { NSString *name; } - (void)setName:(NSString *)aName; @end @implementation User - (void)setName:(NSString *)aName { if (aName != name) { [name release]; name = [aName retain]; } } @endLooks normal, right? But what if I do this:
// don't change that mutable object! NSMutableString *someName = [@"Joe User" mutableCopy]; User user = // ... [user setName: someName]; // okay cool, user's name is now "Joe User" [someName appendString:@" Doodoo Head"]; // oops, user's name and someName point to the same object // which now contains "Joe User Doodoo Head"So even though you thought you were using an immutable
NSString
for your user's name, many common Cocoa Touch classes like NSString
and NSArray
have mutable subclasses, and your object's callers can accidentally give you a mutable instance that they modify later. So when you're writing setters in this situation, you should defensively copy the value you receive.// setter that defensively copies - (void)setName:(NSString *)aName { if (aName != name) { [name release]; name = [aName copy]; } }You can use the
-copy
method if the object implements the NSCopying
protocol, or any creation method that produces a new independent object. (Just make sure to retain that copy if appropriate).Next time, we'll look at how the
@property
and @synthesize
directives are used in modern Objective-C to generate getters and setters automatically.
Friday, April 16, 2010
iPad Friday: April 16, 2010
Hello and happy iPad Friday to all you lucky iPad owners. Today's iPad wallpapers are a continuation of Images of Spring which we began last week. There are the iPhone and iPod touch versions also available for those of us who do not have the magical and revolutionary new mobile device from Apple. Enjoy!
(Click on an image to open the full-size version.)
Tuesday, April 13, 2010
Objective-C Tuesdays: instance variables
See Also
Variables in Objective-C
Last time we talked about local variables and function parameters. Today we will look at instance variables of Objective-C classes and we'll touch on methods as well.Variables in Objective-C
Objective-C classes are defined by an
@interface
section and an @implementation
section. The @interface
section declares the instance variables and looks like this:@interface Cat : NSObject { NSString *name; int age; } - (id)initWithName:(NSString *)aName andAge:(int)anAge; // ... @endThe instance variables (or ivars) are declared between the curly braces, after the class name and superclass but before method declarations. Instance variables are declared like any local or global variable, but have a different scope. By default, instance variables are visible in all instance methods of a class and its subclasses. (Instance methods are the ones that begin with a minus sign.) The implementation of the
-init
method might look like this:// example of using instance variables @implementation Cat - (id)initWithName:(NSString *)aName andAge:(int)anAge { self = [super init]; if ( ! self) return nil; name = [aName copy]; age = anAge; return self; } // ... @endThis is a pretty standard Objective-C
-init
method. Note that unlike JavaScript, Python, Ruby and many other languages, there's no need to prefix instance variables with this
, self
, @
or something similar. But this leads to a problem: what if a method parameter has the same name as an instance variable? If our -init
method was defined like this:// example of name shadowing - (id)initWithName:(NSString *)name andAge:(int)age { self = [super init]; if ( ! self) return nil; name = [name copy]; // causes a warning age = age; // causes a warning return self; }If you compile this code, you'll see warnings like
local declaration of 'name' hides instance variable
. You should heed these warnings! Code likeage = age;assigns parameter
age
to itself, leaving the instance variable age
unchanged.Unfortunately there's no elegant way to deal with parameters shadowing instance variables. Objective-C does allow you to use the "pointer to member" or "arrow" (
->
) operator on self
to access instance variables, like this:// example of pointer to member - (id)initWithName:(NSString *)name andAge:(int)age { self = [super init]; if ( ! self) return nil; self->name = [name copy]; // still causes a warning self->age = age; // still causes a warning return self; }If you know C++ or Java, you would think this would work, but the Objective-C compiler still produces a warning. This is probably one of the most niggling little differences between Objective-C and other languages that you just need to get over. The only practical solution is make sure that parameter names don't clash with instance variables. For initializers and setters, most Objective-C programmers simply prefix their parameter names with "
a
", "an
" or "the
". It's not very elegant, but it works. If you're tempted to simply prefix your instance variable names with an underscore, I recommend against that. Apple uses the leading underscore convention in framework classes in order to prevent name clashes when application writers have to extend framework classes.The
struct
behind the curtainIf you're familiar with C or C++, seeing an expression like
self->name
should give you a clue to the inner workings of Objective-C. Underneath, Objective-C objects are pretty much just struct
s and functions. The @interface
of our Cat
class:@interface Cat : NSObject { NSString *name; int age; } // ... @endbecomes a
struct
that looks something like:// pseudocode for struct generated for Cat class struct Cat { Class isa; // inherited from NSObject NSString *name; int age; };The instance variables you define are tacked on to those defined by the superclass, and its superclass and so on. So if we defined a subclass of
Cat
:@interface LolCat : Cat { UIImage *picture; NSString *caption; int upVotes; } @endthe Objective-C compiler would generate a structure in memory that looked something like:
// pseudocode for struct generated for LolCat class struct LolCat { Class isa; // inherited from NSObject NSString *name; // inherited from Cat int age; // inherited from Cat UIImage *picture; NSString *caption; int upVotes; };Similarly, Objective-C methods are simply regular C functions underneath with extra parameters automatically added by the compiler. So our
-init
method- (id)initWithName:(NSString *)aName andAge:(int)anAge { // ... }is compiled into something that resembles:
// pseudocode for function generated for -initWithName:andAge: method id initWithName_andAge(id self, SEL _cmd, NSString *aName, int anAge) { // ... }The parameters
self
and _cmd
are added to each instance method by the compiler. Naturally, self
is a pointer to the memory for the instance, organized like a struct
as we've shown. The _cmd
parameter holds the method selector (which is basically the method name) and can be used to do very crazy dynamic stuff we won't dive into today.Instance variable scope
We mentioned earlier that by default, instance variables are visible in all instance methods of a class and its subclasses. This is referred to as protected scope in Objective-C. You can change the scope of instance variables to be private, public or package as well as protected, but in general these other scopes aren't used very frequently in Objective-C. Going back to our
Cat
example, you would use the scope specifiers like this:@interface Cat : NSObject { // protected by default double weight; @private int lives; @protected int age; @public NSString *name; @package UIColor *color; } // ... @endPrivate scope restricts visibility of the instance variable to the class it's defined in; subclasses are not allowed to use it. Protected is the default if you don't specify a scope, and allows all subclasses to read and write to the instance variable. Public scope is rarely seen in Objective-C; the pointer to member or arrow (->) operator is used to access public instance variables:
// accessing public instance variables Cat *cat = [[Cat alloc] init]; NSLog(@"The cat's name is %@", cat->name);Package scope is used by framework creators; it makes the instance variable public within the framework and private outside it.
Properties
Since instance variables aren't visible outside classes by default, most Objective-C programmers create getters and setters when they want to expose instance variables. Before Objective-C 2.0, these were written by hand for each instance variable:
// getter and setter declarations @interface Cat : NSObject { NSString *name; int age; } - (NSString *)name; - (void)setName:(NSString *)aName; - (id)age; - (void)setAge:(int)anAge; // ... @endThe normal Objective-C convention is to give the getter the same name as the instance variable and to prefix the setter with "set". The implementation of simple setters is boilerplate but not trivial due to the need to manage retain counts:
// getter and setter definitions @implementation Cat - (NSString *)name { return name; } - (void)setName:(NSString *)aName { if (name != aName) { [name release]; name = [aName copy]; } } // ... @endWriting setters manually is both laborious and error prone, so Objective-C 2.0 introduced properties, allowing getters and setters to be generated automatically. Rewriting the
Cat
class using properties:// property declaration @interface Cat : NSObject { NSString *name; int age; } @property(copy, nonatomic) NSString *name; @property(assign, nonatomic) int age; // ... @endAnd its implementation:
// property implementation @implementation Cat @synthesize name, age; // ... @endWhich is much better. Properties can be called in two ways. Dot notation is the most terse and similar to many other languages:
// property dot notation example Cat *cat = [[Cat alloc] init]; NSLog(@"The cat is %d years old", cat.age); cat.name = @"Ritz";But you can use normal method calls as well:
// property method call example Cat *cat = [[Cat alloc] init]; NSLog(@"The cat is %d years old", [cat age]); [cat setName:@"Ritz"];These two examples are exactly equivalent. Dot notation is simply syntactic sugar for getter and setter method calls.
Which is which?
While it's very convenient, property dot notation makes Objective-C a little confusing at first. You will sometimes see properties and instance variables mixed together in the same method:
- (void)celebrateBirthday { age++; // instance variable if (age > 9) { self.name = // property [NSString stringWithFormat:@"Old %@", name]; // instance variable } }At first glance,
name
and self.name
don't seem that different but they are. We'll examine those differences, and look more at properties, next time.
Friday, April 9, 2010
iPad Friday: April 9, 2010
Hello all you lucky owners of a magical and revolutionary new mobile device (and you know who you are). Here are a set of iPad wallpapers from today's iPhone Friday scaled to fit your beautiful display. Enjoy!
(Click the image for the full-size image)
(Click the image for the full-size image)
iPhone Friday - April 9, 2010
Hello and happy Friday to you all. Today's iPhone and iPod touch wallpapers come from a response to the iPad wallpapers from last week (thank you Carmen). They are some pictures I took the garden yesterday. I have cropped them down for iPhone/iPod touch and will also post a follow-up entry for the iPad as well. Cheers!
Tuesday, April 6, 2010
Objective-C Tuesdays: local variables and function parameters
See Also
Variables in Objective-C
Last time when we looked at Variables in Objective-C
static
variables declared inside functions, we touched on local variables. Today we'll focus on local variables and function parameters.Local variables in C and Objective-C are declared like this:
// local variable examples void myFunction() { // declare some local variables ... int i; // uninitialized, will have some random value NSString *s = @"foobar"; double sqrtOf2 = sqrt(2); // do stuff ... }Local variables are not initialized to zero,
NULL
or nil
by default the way global variables are. It's important to initialize a local variable before you use it, otherwise its initial value will be something random and almost certainly not something useful. Function parameters are very similar to local variables, except that their value is defined by the caller of the function.// function parameter examples void yourFunction(int i, NSString *s, double d) { // do stuff ... }In very old C code, you may sometimes see function parameters declared like this:
// old function parameter style myOldFunction(i, s, d) // only parameter names go here int i; NSString *s; double d; // parameter types are defined between // the parameter list and curly brace { // do stuff ... }This old style is called K&R C (for Kernighan & Ritchie, the authors of The C Programming Language book) and has been replaced by the modern ANSI C style you're used to, but you many occasionally see it in very old code or examples. (In fact, the function return type is optional in K&R C and defaults to
int
if not given.)Function parameters are available for the complete time that the function is executing. Local variables however can have a more limited lifespan. Typically, local variables are local to a function body, but they can also be local to the body of an
if
, for
, while
and do-while
statement:void printSquares() { int x; for (x = 0; x < 10; ++x) { int x_squared = x * x; // only valid in the for loop printf("%i^2 = %i\n", x, x_squared); } // x_squared no longer valid // x still valid }In fact, you can even use a set of curly braces alone to create a new local variable scope:
void someFunction() { int x; // new local scope { int foo = 10; // local variable foo now valid // ... do something with foo } // foo no longer valid // x still valid }In older versions of C and Objective-C, all local variables had to be declared at the start of a function or statement block. So something like this:
void someFunction() { int x = 10; printf("x = %d\n", x); int y = 20; // not allowed before C99 printf("y = %d\n", y); }would not compile. The C99 standard changed this to allow local variables to be declared at any point in a function, something that C++ has always allowed. By default, Xcode Objective-C projects compile using C99 rules (this is set by the C Language Dialect build setting in Xcode or the
-std=c99
command line parameter to gcc
).Next time, we will look at instance variables of Objective-C classes.
Monday, April 5, 2010
Tired of iPad hype? Get excited about iPhone OS 4!
Did you spend the weekend playing with your iPad? (I did :-) Or are you waiting impatiently for the iPad 3G models to arrive later this month? Tired of all the hype already? Well Apple's not giving you a break yet. Gizmodo is reporting this morning that invitations have gone out for a "sneak peak into the future of iPhone OS." The event is this Thursday, 8 April at 10 AM Pacific time.
Anyone want to guess what new features are in store? Multitasking? iPhone versions of Pages and Numbers? New phone hardware? iPhone on Verizon's network? A front-facing camera for video chat? All I know is that Apple will surely surprise and delight.
Anyone want to guess what new features are in store? Multitasking? iPhone versions of Pages and Numbers? New phone hardware? iPhone on Verizon's network? A front-facing camera for video chat? All I know is that Apple will surely surprise and delight.
Saturday, April 3, 2010
iPad Wallpaper: April 3, 2010
Hello, new friend. I will hug you and pet you and name you George. (That's short for "gorgeous" which is exactly what Apple's iPad is.) Today Apple is releasing their latest mobile device which both Don and I, along with friends, will be picking up today. Woot!
In honor of this event I am providing you (the fortunate ones to pick up an iPad) with eight iPad wallpaper images at a beautiful 1024 x 767 pixel resolution. I have created more but I think eight will be a good start, and you may like one of them.
(Click on an image to open the full-size version.)
In honor of this event I am providing you (the fortunate ones to pick up an iPad) with eight iPad wallpaper images at a beautiful 1024 x 767 pixel resolution. I have created more but I think eight will be a good start, and you may like one of them.
(Click on an image to open the full-size version.)
Subscribe to:
Posts (Atom)