ObjectiveC——类
Class的定义
1:调用系统的类
eg:
class pointer to obejct object
NSString *message = @"Hello";
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
注:在ObjectiveC中所有的类的实例都用指针表示
相比较普通变量实例存储的是内存里直接申请的空间,存储值本身,而object实例存储的是指针地址,指向类的object在内存的位置。
Define/Using Pointer
NSString *message; //define pointer
message = @"Hello"; //use pointer
eg:
1 #import <Foundation/Foundation.h> 2 3 void myFunction(NSString *foo); { 4 //定义NSString的指针作为参数 5 NSLog(@"The message was %@", foo); 6 //使用指针不需要写*,pointer的placeholder是%@ 7 } 8 9 int main(int argc, const char * argv[]) 10 { 11 NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 12 NSString * message = @"Hello"; 13 //定义一个指向NSString的指针 14 15 myFunction(message); //使用指针不需要写* 16 [pool drain]; 17 return 0; 18 }
Call Object's methord
1: Normal Methord Call
c# myObject.someMethord(arg);
ObjectiveC [myObject someMethord:arg];
c# myObject.insertString("Hello", 11);
ObjectiveC [myObject insertString: @"Hello" atIndex:11]; //each parameter is named
eg:
1 [NSFileManager replaceItemAtURL: 2 withItemAtURL: 3 backupItemName: 4 options: 5 resultingItemURL: 6 error: 7 ];
2: Nested Methord Call
[myObject someMethord:[anotherObject anotherMethord]];
Class Methord VS Instance Methord
1 NSString *message = @"Hello"; 2 MSString *message2 = [message uppercaseString]; 3 //uppercaseString是Instance Methord,需要从一个object call 4 //uppercaseString的返回值是一个指针,所以要返回给一个新的指针 5 6 NSLog(@"The result is %@", message2); 7 8 //注:调用methord需要用[]框起来 9 10 NSDate *myDate = [NSDate date]; 11 //[NSDate date]是class methord直接使用,不需要一个object承载 12 NSLog(@"The date is %@", meDate);
Creating an Object
New Methord:
new方法创建object的三步过程:(注:所有的class都有new方法)
- Allocation:ObjectiveC到内存里挖出一块object大小的空间
- Initialization:对object进行初始化Variable
- Return:返回object的地址到指针变量(myDate)
拆写new:(为什么要拆开? 因为init有多种不同的初始化方法,new只有一种初始化方式)
实际工作中我们经常分开实现new的功能:
- NSDate ×myDate = [NSDate alloc]; 1:创建了一个NSDate的对象, 2:返回指向这个对象的指针
- myDate = [myDate init]; 对象初始化步骤,set variables
实际上我们可以合并写成一句:
NSDate *myDate = [[NSDate alloc] init];
eg:
Class *myObj = [[Class alloc] init]; Person *fred = [[Person alloc] init]; Dog *fido = [[Dog alloc] init]; Customer *acmeCorp = [[Customer alloc] init]; NSAutoReleasePool *pool = [[NSAutoReleasePool alloc] init];
Memory Management
1:Release now
使用拆分发或者new方法创建的object,你拥有该object,记得使用完后要release。 Iphone Ipad app和2011年前创建的Mac App都需要清除不用的memory。
NSDate *myDate = [[NSDate alloc] init];
...... //use NSDate object
double seconds = [myDate timeIntervalSince1970];
//使用完后
[myDate release]; //清除不用的内存
myDate = nil; //清除不用的指针(不是必须要写)
还有什么方法关键词代表用户清除Memory的责任?
alloc, new, retain, copy
我们使用alloc一次,需要release一次,retainCount计数从1->0.
我们做了init,和三次retain,retainCount为4,我们需要清除四次使retainCount回0
2:AutoRelease:
[fred autorelease]; //把这个object放到release pool里
... //some times in future一次清除pool
[pool drain]; //程序自动调用release
3: When to use autorelease?
你创建一个类可以创建对象并返回
createEmployee{
//create a new object
Employee *fred = [[Employee alloc] init];
[fred autorelease];
return fred;
} //谁调用这个class创建对象,那么就是他的责任去release 他创建的内存
创建自定义类
相关知识:
ObjectiveC里class分成两个file:interface, implementation
interface .h file: 描述class都有什么methord,有什么变量,什么是aviable的。
implementation .m file:Real code of class
1:New->File
2:Objective-C class
3:选择所创建子类的继承类,这里是NSObject:(NSObject是super父类,任何类都是继承它的)
4:Employee类创建成功
分成两个file的好处是,很多情况我们看apple的源代码,我们只要看.h就可以知道class是做什么用的。
不象其他语言需要写class关键字,ObjectiveC的class就是@interface和@impelemntation
5:实例
.h
1 #import <Foundation/Foundation.h> 2 3 @interface Employee : NSObject 4 5 @property NSString *name; 6 @property NSData *hireDate; 7 @property int employeeNumber; 8 //分别定义了类的三个data,即三个property 9 10 -(void) someMethord; //定义该类的behivor,即方法。 返回类型要加()。 "-"代表这个类是instance class 11 12 @end
.m
1 #import "Employee.h" 2 3 @implementation Employee 4 5 @synthesize name, hireDate, employeeNumber; //Xcode自动为三个变量generate了两个方法,get; set; 6 7 -(void) someMethord{ 8 NSLog(@"In the methord"); 9 } 10 @end
main.m 调用我们自己的class
1 #import <Foundation/Foundation.h> 2 #import "Employee.h" //import自己的project file用“” 3 4 int main(int argc, const char * argv[]) 5 { 6 7 @autoreleasepool { 8 9 // insert code here... 10 Employee *fred = [[Employee alloc]init]; //alloc和init方法虽然我们没定义但是都继承自NSObject 11 [fred someMethord]; 12 } 13 return 0; 14 }
6:补充
.h文件 #import <Foundation/Foundation.h> @interface Person : NSObject @end .m文件 #import "Person.h" @implementation Person -(id)init { self = [super init]; if(self){ //Initialization code here } return self; } @end
我们可以看到,Xcode自动为我们加载一些代码,并以文件名为类名。@interface Person : NSObject;
在@interface关键字后的就是类名。
自创类的方法
概念:任何方法都是为一个类而创建的,ObjectiveC的方法分为两类,实例的方法和类的方法。前者用“-”表示,需要实例化一个实例才可以用,后者用“+”表示,不需要实例化在类的范围内使用。
带参数方法的定义:
- 类的返回类型:如(void), (Bool), (NSObject *)
- 方法名用camal记法
- 方法的参数可以有多个,除了第一个参数,后面每个参数都由两部分组成,前半部分是方法名的延续,后一部分是参数名,之间用“:”分开
- 记得后半部分的参数用“()”表示数据类型
单个parameters
- (int) timesTen : (int) param;
-(NSString *) createMessage : (NSString *) input; //函数接受一个NSString指针并返回一个NSString指针
多个parameters
-(int) addNumberz : (int) a toNumber : (int) b;
methord name: param type + name 2nd part methord name: param type + name
Instance Methord的创建:
-(int) addNumberz: (int) a toNumber: (int) b; 或者: -(BOOL) sendEmailTo:(NSString *)paramTo withSubject:(NSString *)paramSubject andEmailMessage:(NSString *)paramEmailMessage{ // Send the email and return an appropriate value if([paramTo length]==0 || [paramSubject length]==0 || [paramEmailMessage]==0){ //one or some of the parameters are empty NSLog(@"Empty parameter is/are provided."); return NO; } return YES;
}
这是一个instance methord(-),返回值是(BOOL). 方法名是 sendEmailTo : withSubject : andEmailMessage, 有三个参数,call function in this way.
[self sendEmailTo:@"someone@somewhere.com" withSubject:@"My Subject" andEmailMessage:@"Please read my email."];
Class Methord的创建:
创建一个allocAndInit在class里,可以同时达到allocate and initialize对象并返回对象给他的caller
//This is MyClass.h #import <Foundation/Foundation.h> @interface MyClass : NSObject +(id) allocAndInit @end //Implement the Class Methord, this is MyClass.m #import "MyClass" @implementation MyClass +(id) allocAndInit{ MyClass *result = [[MyClass alloc] init]; return result; } @end
In our app delegate we can use this class methord to allocate and initialize an instance of MyClass.
//this is AppDelegate.m file
#import "AppDelegate.h" #import "MyClass.h" @implementation AppDelegate @synthesize window = _window; -(BOOL) application:(UIApplication *)application didFinishLaunchingWithOption:(NSDictionary *)launchOptions{
MyClass *instance1 = [MyClass allocAndInit]; NSLog(@"Instance 1 = %@", instance1); self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; }
3:
.h
1 #import <Foundation/Foundation.h> 2 3 @interface MyClass : NSObject 4 5 -(void) performAction: (int) param; 6 -(int) addNumber: (int) a toNumber: (int) b; 7 8 @end
.m
1 #import "MyClass.h" 2 3 @implementation MyClass 4 5 -(void)performAction:(int)param{ 6 NSLog(@"You passed in the value %i", param); 7 } 8 9 -(int)addNumber:(int)a toNumber:(int)b{ 10 return a+b; 11 } 12 13 @end
自创类的变量
这里我们定一个instance变量,该变量只能这个类内部调用,如果我们要别的文件也可以访问这个变量,我们需要创建get;set方法
.h
1 @interface Player : NSObject 2 { 3 //instance variables 4 int score; //所有需要定义的变量写在{}里 5 } 6 7 -(int) score; //getter 8 -(void) setScore: (int) amount; //setter 9 10 @end
.m
1 @implementation Player 2 // accessor methord 3 -(int) score{ 4 return score; 5 } 6 7 -(void) setScore : (int) amount{ 8 score = amount; 9 } 10 11 @end
自创类的属性
上面通过get;set方法访问instance 变量有些麻烦,我们可以用property来替代,property会自动创建get;set方法
上述代码替换成property简化多了
.h
1 @interface Player : NSObject 2 { 3 //instance variables 4 int score; //所有需要定义的变量写在{}里 5 } 6 @property int score; //同样type和name的property会自动wrap上面的score 7 8 @end
.m
1 @implementation Player 2 @synthesize score; 3 4 5 @end
随着xcode的升级4.4+,定义property更简单了:
.h 是public face of class
1 @interface Player : NSObject2 @property int score; 3 4 @end
.m 如果还要定义instance variable供class内部使用,{var1, var2}加在@implementation下面
1 @implementation Player 2 3 @end
property是有自己的属性的:
@property (strong) NSString * firstName; //strong reference to NSString *:We own it, as long as we use ARC will take care it
@property (readonly) int * employeeID; //just synthesize a getter methord
关于property和variable的总结:
- interface .h 只放property 和方法的声明
- implemtation .m 放内部使用的变量,和方法的具体实现
.h的结构
1 @interface Player : NSObject 2 3 //各种property的声明,property可以带自己的属性 4 @property int score; 5 @property (strong) NSString * firstName 6 ... 7 8 //各种方法的声明 9 //methords 10 ... 11 12 @end
.m的结构
1 @implementation Player 2 { 3 //各种内部var的定义 4 int year; 5 float speed; 6 .... 7 } 8 9 //各种方法的具体实现 10 //-methord 11 12 @end
Initializers
MyClass *myObj = [[MyClass alloc] init];
//所有的类都有init方法,因为继承自NSObject
custom init:
在Xcode我们可以从snipy里拉出一个init看看
.m
#import "MyClass.h" @implementation MyClass - (id)init //代表可以返回任何object { self = [super init]; //self相当于this,本object自己,super代表NSObject,调用其init方法 if (self) { <#initializations#> //如果self存在则这里就是我们需要custom的init代码段
score = 5000; } return self; } @end
.h
#import <Foundation/Foundation.h> @interface Player : NSObject @property int score; @end
main.m
#import <Foundation/Foundation.h> //调用apple的API就<> #import "Player.h" //调用本项目里的文件就"" int main(int argc, const char * argv[]){ @autoreleasepool{ //insert code here... Player * p = [[Player alloc] init]; NSLog(@"The score is %i", p.score) } return 0; }
这就是ObjectiveC的init,相对于C#里的构造函数: 这里总是有alloc,regular init,和more custom init methods(看下NSData下有很多不同
-init methord,分别对应不同的参数或者返回值的初始化函数)
.m
#import "MyClass.h" @implementation MyClass
- (id)initWithInt : (int) s //NSObject里没有我们这个custom的init名字,所以我们要在.h里声明 { self = [super init]; //self相当于this,本object自己,super代表NSObject,调用其init方法 if (self) { <#initializations#> //如果self存在则这里就是我们需要custom的init代码段
score = s; } returnself; }
- (id)init //因为这时默认NSObject的init方法,所以.h里不用声明 { self = [super init]; //self相当于this,本object自己,super代表NSObject,调用其init方法 if (self) { <#initializations#> //如果self存在则这里就是我们需要custom的init代码段
score = 5000; } return self; }
} @end
.h
#import <Foundation/Foundation.h> @interface Player : NSObject
- (id)initWithInt : (int) s //我们需要做这一步,因为我们initWithInt在别的file里调用的时候是可见的 @property int score; @end
main.m
#import <Foundation/Foundation.h> //调用apple的API就<> #import "Player.h" //调用本项目里的文件就"" int main(int argc, const char * argv[]){ @autoreleasepool{ //insert code here... Player * p = [[Player alloc] init]; NSLog(@"The score is %i", p.score);
Player *x = [[Player alloc] initWithInt: 7500];
NSLog(@"The Scroe value is %i", [x score]); //换成x.score也可以
} return 0; }
最后如果一个init方法包含了另外一个我们可以简单写:
#import "MyClass.h" @implementation MyClass
- (id)initWithInt : (int) s //NSObject里没有我们这个custom的init名字,所以我们要在.h里声明 { self = [super init]; //self相当于this,本object自己,super代表NSObject,调用其init方法 if (self) { <#initializations#> //如果self存在则这里就是我们需要custom的init代码段
score = s; } returnself; }
- (id)init //因为这时默认NSObject的init方法,所以.h里不用声明 { return [self initWithInt:5000]; }
} @end