- alloc
- Polymorphism
- self
- super
- protected
- Instance Variables and Accessors - self->ivar
- Key-Value Coding
- Properties
<alloc>
The alloc class method is implemented by the NSObject class, the root class from which all other classes inherit it. 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. Therefore you can, and always should, call alloc and the initializer in the same line of code.
SomeClass* aVariable = [[SomeClass alloc] init];
The above is to nest the alloc call in the initialization call, assigning the result of the initialization (not the alloc!) to a variable.
<Polymorphism>
Polymorphism is related to inheritance.
We have a class Shape that provides the basic interface for all the shapes. Square and Rectangle are derived from the base class Shape.
#import <Foundation/Foundation.h> @interface Shape : NSObject{ CGFloat area; } - (void)printArea; @end
@implementation Shape - (void)printArea{ NSLog(@"The area is %f", area); } @end |
@interface Square : Shape{ CGFloat length; } - (id)initWithSide:(CGFloat)side; - (void)calculateArea; @end
@implementation Square
- (id)initWithSide:(CGFloat)side{
length = side;
return self;
}
- (void)calculateArea{
area = length * length;
}
- (void)printArea{
NSLog(@"The area of square is %f", area);
}
@end
|
@interface Rectangle : Shape{ CGFloat length; CGFloat breadth; } - (id)initWithLength:(CGFloat)rLength andBreadth:(CGFloat)rBreadth; @end @implementation Rectangle - (id)initWithLength:(CGFloat)rLength andBreadth:(CGFloat)rBreadth{ length = rLength; breadth = rBreadth; return self; } - (void)calculateArea{ area = length * breadth; } @end int main(int argc, const char * argv[]){ NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Square *square = [[Square alloc]initWithSide:10.0]; [square calculateArea]; [square printArea]; Rectangle *rect = [[Rectangle alloc] initWithLength:10.0 andBreadth:5.0]; [rect calculateArea]; [rect printArea]; [pool drain]; return 0; } |
When the above code is compiled and executed, it produces the following result:
2013-09-22 21:21:50.785 Polymorphism[358:303] The area of square is 100.000000 2013-09-22 21:21:50.786 Polymorphism[358:303] The area is 50.000000 |
The method printArea can be either in the base class or the derived class is executed.
Please note that unlike in Objective-C, we cannot access the superclass printArea method in case the method is implemented in the derived class. <-???
Source: http://www.tutorialspoint.com/objective_c/objective_c_polymorphism.htm
Another example
UIButton* b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; UIView* v = b; [v setTitle:@"Howdy!" forState:UIControlStateNormal]; |
That code will cause the compiler to complain, because UIView doesn’t implement set-
Title:forState:; under ARC, in fact, that code won’t even compile. So I’ll calm the
compiler’s fears by typecasting:
UIButton* b = [UIButton buttonWithType:UIButtonTypeRoundedRect]; UIView* v = b; [(UIButton*)v setTitle:@"Howdy!" forState:UIControlStateNormal]; |
The Keyword Self
An instance method defined in a class must call another instance method defined within the same class. A method is called by sending a message to an object;
@implementation Dog - (NSString*) bark { return @"Woof!"; } - (NSString*) speak { return [self bark]; } @end |
@implementation Basenji : Dog - (NSString*) bark { return @""; // empty string, Basenjis can't bark } @end |
Basenji* b = [Basenji new]; NSString* s = [b speak]; |
The keyboard self does not actually mean "in the same class". It's an instance, after all, not a class.
We have a class Dog with an instance method bark and also another instance method speak, which simply call bark.
Now suppose we subclass Dog with a class Basenji, which overrides bark (because Basenji can't bark). What happens when we send the speak message to a Basenji instance?
The speak message is sent to our Basenji instance, b. The Basenji class doesn’t implement a speak method,so we look upward in the class hierarchy and discover that speak is implemented in the superclass, Dog. We call Dog’s instance method speak, the speak method runs, and the keyword self is encountered.
It means “the instance to which the original message was sent in the first place.” That instance is still our Basenji instance b. So we send the bark message to the Basenji instance b. The Basenji class implements a bark instance method, so this method is found and called, and the empty string is returned.
The Keyword Super
Sometimes (quite often, in Cocoa programming) you want to override an inherited method but still access the overridden functionality. To do so, you’ll use the keyword super.The keyword super is class-based.
Suppose we define a class NosiyDog, a subclass of Dog. When told to bark, it barks twice:
@implementation NoisyDog : Dog - (NSString*) bark { return [NSString stringWithFormat: @"%@ %@", [super bark], [super bark]]; } @end |
That code calls super’s implementation of bark, twice; it assembles the two resulting
strings into a single string with a space between, and returns that (using the stringWith-
Format: method). Because Dog’s bark method returns @"Woof!", NoisyDog’s bark
method returns @"Woof! Woof!". Notice that there is no circularity or recursion here:
NoisyDog’s bark method will never call itself.
<Instance Variables and Accessors - self->ivar>
Instance variables (ivar) are protected, meaning the other classes (except for sub-classes) can't see them. But in general, you want to provide public access to an instance variable, write an accessor method (i.e. getter / setter methods) and make the method declaration public.
Within a class, on the other hand, that class’s own instance variables are global. Any Dog method can just use the variable name number and access this instance variable, just like any other variable.
But code that does this can be confusing when you’re reading it; suddenly there’s a variable called number and you don’t understand what it is, because there’s no nearby declaration for it. So I often use a different notation, like this: self->ivarName, where -> is called the structure pointer operator, because of its original use in C.
@implementation Dog {
int number;
}
- (void) setNumber: (int) n {
self->number = n;
}
- (int) number {
return self->number;
}
@end
Of course, to make setNumber: public to any other class that imports Dog’s interface
file, we must also declare it in Dog’s interface section:
@interface Dog : NSObject
- (void) setNumber: (int) n;
@end
We can now instantiate a Dog and assign that instance a number:
Dog* fido = [Dog new];
[fido setNumber: 42];
We can now set a Dog’s number, but we can’t get it (from outside that Dog instance). To
correct this problem, we’ll write a second accessor method, one that allows for getting
the value of the number ivar:
- (int) number {
return self->number;
}
Again, we declare the number method in Dog’s interface section. Now we can both set
and get a Dog instance’s number:
Dog* fido = [Dog new];
[fido setNumber: 42];
int n = [fido number];
// sure enough, n is now 42!
You can talk like this:
fido.number = 42;
int n = fido.number;
If you want them to be publicly accessible, you must provide accessor methods.
Luckily, Objective-C 2.0 — which is what you’re using to program for iOS — provides a mechanism for generating accessor methods automatically.
Usually, we follow the convention and rename our ivar with an underscore: _number:
@implementation Dog {
int _number;
}
- (void) setNumber: (int) n {
self->_number = n;
}
- (int) number {
return self->_number;
}
@end
<Key-Value Coding> <-- Q: when need to use this?
Instead of calling [fido number], we might have a string @"number" that tells us what accessor to call. This string is the “key.” The key–value coding equivalent of calling a getter is valueFor-Key:; the equivalent of calling a setter is setValue:forKey:.
Even though the number instance variable is an int, the value returned by valueFor-
Key: is an object — in this case, an NSNumber, the object equivalent of a number.
If we want the actual int, NSNumber provides an instance method, int-Value, that lets us extract it:
NSNumber* num = [fido valueForKey: @"number"];
int n = [num intValue];
Similarly, to use key–value coding to set the value of the number instance variable in the
fido instance, we would say:
NSNumber* num = [NSNumber numberWithInt:42];
[fido setValue: num forKey: @"number"];
we can rewrite the previous example like this:
NSNumber* num = @42;
[fido setValue: num forKey: @"number"];
In real life, you’d probably omit the intermediate variable num and write the whole thing as a single line of code:
[fido setValue: @42 forKey: @"number"];
<Properties>
I’ll use the Dog class as an example. If the Dog class has a public getter method called
number and a public setter method called setNumber:, then the Dog class also has a
number property. This means that, instead of saying things like this:
[fido setNumber: 42];
int n = [fido number];
You can talk like this:
fido.number = 42;
int n = fido.number;
Your use of property syntax is entirely optional. The existence of a property is equivalent to the existence of the corresponding getter and setter methods, and you’re free to call those methods by either syntax.
Notes:
* Do not confuse a property with an instance variable.
Instance variable:
self->number = n
or even simply
number = n
Property is equivalent to calling a getter or setter method:
fido.number
or
self.number
That getter or setter method may access an instance variable, and that instance variable may even have the same name as the property, but that doesn’t make them the same thing.
Java 中的 interface 到了 Objective-C 叫做 protocol.
Dynamic Typing
Discovering the class of an object at runtime rather than at compile time.
Dynamic Binding
Binding a method to a message—that is, finding the method implementation to invoke in response to the message—at runtime, rather than at compile time.
No comments:
Post a Comment