IOS4 note 10 (Chapter 5)How Instances Are Created??Your class objects are created ?for you automati
IOS4 note 10 (Chapter 5)
How Instances Are Created
?
?
Your class objects are created ?for you automatically as your program starts up, but?instances must be ?created deliberately ?as ?the program ?runs. The ?entire question of?where instances come from is thus crucial. Ultimately, every instance comes into existence in just one way: someone turns to a class and ask that class to instantiate itself.
But there are three different ways in which this can occur: ready-made instances, instantiation from scratch, and nib-based instantiation.?
?
?
Ready-Made Instances
?
?
One way to create an instance is indirectly, by calling code that does the instantiation for you. You can think of an instance obtained in this indirect manner as a “ready-made instance.” (That’s my made-up phrase, not an official technical term.) For example, consider this simple code:
NSString* s2 = [s uppercaseString];
The NSString produced by the uppercaseString method is a ready-made NSString instance. Your code didn’t say anything about instantiation; it just sent the uppercaseString message. But clearly someone said something about instantiation, because instantiation took place; this is a newly minted NSString instance. That someone is presumably some code inside the NSString class. But we don’t have to worry about the details. We are guaranteed of receiving a complete ready-made ready-to-roll NSString,and that’s all we care about.
Instantiation from ScratchThe alternative to requesting a ready-made instance is to tell a class, yourself, directly,to instantiate itself. There is basically one way to do this: you send a class the alloc message. The alloc class method is implemented by the NSObject class, the root class from which all other classes inherit. It causes memory to be set aside for the instance so that an instance pointer can point to it.You must never, never, never call alloc by itself. You must immediately call another?method, an instance method that initializes the newly created instance, placing it into?a known valid state so that it can be sent other messages. Such a method is called an?initializer. Moreover, an ?initializer returns an ?instance — usually the same ?instance,?initialized. Therefore you can, and always should, call alloc and the initializer in the?same line of code. The minimal initializer is init. So the basic pattern, known informally?as “alloc-init,” looks like Example 5-1.Example 5-1. The basic pattern for instantiation from scratchSomeClass* aVariable = [[SomeClass alloc] init];
The designated initializer
If a class does define initializers, one of them may be described in the documentation?as the designated initializer. (There’s nothing about a method’s name that tells you it’s?the designated initializer; you must peruse the documentation to find out.) For example, in the UIView class documentation, the initWithFrame: method is described as the?designated initializer. A class that does not define a designated initializer inherits its?designated initializer; the ultimate designated initializer, inherited by all classes without?any other designated initializer anywhere in their superclass chain, is init.
Nib-Based InstantiationA nib file (whose extension may be .nib or .xib) is where Xcode lets you "draw" parts of the user interface, and will then be loaded as the app runs. A nib file consists, in a sense, of the names of classes along with instructions for instantiating and initializing them. When the app runs and a nib file is loaded, those instructions are carried out -- those classes are instantiated and initialized.The fact that nib files are a source of instances, and that those instances are brought?into existence as the nib file is loaded.
PolymorphismThe compiler, even in the world of static typing, is perfectly happy for you to supply a?subclass instance where a superclass type is declared. To see this, let’s start with the?first line of the previous example:?UIButton* b = [UIButton buttonWithType:UIButtonTypeRoundedRect];UIButton ?is a subclass of UIControl, which ?is a subclass of UIView. So ?it would be?perfectly legal and acceptable to say this:UIButton* b = [UIButton buttonWithType:UIButtonTypeRoundedRect];UIView* v = b;we treated a UIButton object as a UIView, yet we were still able to send it?a UIButton message. We treated a UIButton as a UIButton, yet we were still able to?send it a UIView message. What matters when a message is sent to an object is not how?the variable pointing to that object is declared but what class the object really is. What?an object really is depends upon its class, along with that class’s inheritance from the?superclass chain; these facts are innate to the object and are independent of how the?variable pointing to the object presents itself to the world. This independent maintenance of object type integrity is the basis of what is called polymorphism.But it is not quite the whole of polymorphism. To understand the whole of polymorphism, we must go further into the dynamics of message sending.
Instance Variablesone of the main reasons there are instances and not just classes is that instances can have instance variables.By default, instance variables are protected, meaning that other classes (except for subclasses) can’t see them. So if, somewhere else, I instantiate a Dog, I won’t be able to access ?that Dog ?instance’s ?number ?instance ?variable. This ?is ?a ?deliberate ?feature ?of Objective-C; you can work around it if you like, but in general you should not. Instead, if you want to provide public access to an instance variable, write an accessor method and make the method declaration public.Within a class, on the other hand, that class’s own instance variables are global. Any But global variables can be confusing when you’re reading code; suddenly there’s a variable called number and you don’t understand what ?it ?is, because there’s no declaration for it (the declaration is stashed away in the interface?section, which ?is ?in ?a ?different ?file). ?So ?I ?often ?use ?a ?different ?notation, ?like ?this:self->ivarName. The “arrow” operator, formed by a minus sign and a greater-than sign,is called the structure pointer operator, because of its original use in C.
Key–Value CodingObjective-C provides a means for translating from a string to an instance variable accessor, called key–value coding. Such translation is useful, for example, when the name?of the desired instance variable will not be known until runtime. So, for example, instead of ?calling ?[fido number], we might have a ?string ?@"number" ?that ?tells us what?accessor to call. This string is the “key.” To use key–value coding to get the value of?the number instance variable from the fido instance, we would say:?int n = [fido valueForKey: @"number"];
PropertiesA property is a syntactical feature of Objective-C 2.0 designed to provide an alternative?to the standard syntax for calling an instance variable accessor.To use a property within the class that declares that property, you must use self explicitly. So, for example:self.number = 42;Do not confuse a property with an instance variable. An expression like?self->number = n, or even simply number = n, sets the instance variable?directly (and is possible only within the class, because instance variables?are ?protected ?by ?default). ?An ?expression ?like ?fido.number ?or?self.number involves a property and is equivalent to calling a getter or?setter method. That getter or setter method may access an instance variable, and that instance variable may have the same name as the property, but that doesn’t make them the same thing.Objective-C uses dot-notation for properties, and C uses dot-notation for structs; these?can be chained. So, for example, UIView’s frame is a property whose value is a struct?(a CGRect); thus, you can say myView.frame.size.height, where frame is a property that?returns ?a ?struct, ?size ?is ?a ?component of ?that ?struct, ?and ?height ?is ?a ?component?of?that struct. But a struct is not a pointer, so you cannot (for example) set a frame’s height?directly through a chain starting with the UIView, like this:myView.frame.size.height = 36.0; // compile errorInstead, if you want to change a component of a struct property, you must fetch the?property value into a struct variable, change the struct variable’s value, and set the entire?property value from the struct variable:CGRect f = myView.frame;f.size.height = 0;myView.frame = f;
How to Write an Initializer- (id) initWithNumber: (int) nOur return value is typed as id, not as a pointer to a Dog, even though in fact we will?return a Dog object. This is a convention that we should obey. The name is conventional?as well; as you know, the init beginning tells the world this is an initializer.- (id) initWithNumber: (int) n {? ? self = [super init]; ??? ? if (self) {? ? ? ? self->number = n;?? ? }? ? return self;?}The parts of the convention are:
1.We send some sort of initialization message, calling a designated initializer. If this?is our class’s designated initializer, this message is sent to super and calls the superclass’s designated initializer. Otherwise, it is sent to self and calls either this class’s?designated initializer or another initializer that calls this class’s designated initializer.In this case, this is our class’s designated initializer, and the superclass’s designated?initializer is init.
2.We capture the result of the initialization message to super, and assign that result?to self. It comes as a surprise to many beginners (and not-so-beginners) that one?can assign to self at all or that it would make sense to do so. But one can assign to?self (because of how Objective-C messaging works behind the scenes), and it makes?sense to do so because in certain cases the instance returned from the call to super?might not be same as the self we started with.
3.If self is not nil, we initialize any instance variables we care to. This part of the code?is typically the only part you’ll customize; the rest will be according to the pattern.?Observe that I don’t use any setter methods; in initializing an instance variable not?inherited ?from ?the superclass, you should assign directly ?to ?the ?instance variable?(and if it’s an object, you’ll also have to do some memory management, to be explained in Chapter 12).
4.We return self.But we are not finished. Recall from earlier in this chapter that a class that defines a?designated initializer should also override the inherited designated initializer (in this?case, ?init). ?And ?you ?can ?see ?why: ?if ?we ?don’t, ?someone ?could ?say?[[Dog alloc] init] and create a dog without a number — the very thing our initializer?is trying to prevent. Just for the sake of the example, I’ll make the overridden init assign?a negative number as a signal that there’s a problem. Notice that we’re still obeying the?rules: this initializer is not the designated initializer, so it calls this class’s designatedinitializer.- (id) init {? ? return [self initWithNumber: -9999];}All instance variables are set to a form of zero by alloc. Therefore, any?instance variables not initialized explicitly in an initializer remain 0. This?means, among other things, that by default a BOOL instance variable?is NO ?and ?an object ?reference ?instance ?variable ?is nil. ?It ?is ?common?practice to take advantage of these defaults in your program; if the default values are satisfactory initial values, you won’t bother to set them?in your designated initializer.
?