类定义
在OC中,一般用二个文件描述一个类,一个是.h文件,一个是.m文件爱你:
1>:.h文件是类的声明文件,用于声明变量和方法。类的声明使用关键字@interface和@end。
2>:.m文件是类的实现文件,用于实现.h类中声明的方法。类的实现使用关键字@implementation和@end。
方法
1> 方法的声明和实现,都必须以 + 或者 - 开头
- + 表示类方法(静态方法)
- - 表示对象方法(动态方法)
2> 在.h中声明的所有方法作用域都是public类型,不能更改
成员变量
成员变量的常用作用域有3种:
1> @public 全局都可以访问
2> @protected 只能在类内部和子类中访问
3> @private 只能在类内部访问
方法和属性
1.Student.h类的声明文件
1 #import <Foundation/Foundation.h> 2 3 @interface Student : NSObject { 4 5 int age; 6 @public 7 int no; 8 int score; 9 10 @protected 11 float height; 12 13 @private 14 float weight; 15 } 16 - (int)age; 17 - (void)setAge:(int)newAge; 18 - (void)setAge:(int)newAge :(float)newHeight; 19 @end
1>第3行:用@interface声明一个类Student,后面紧跟着的:表示继承与NSObject
2>第5行:定义了一个int类型的成员变量age,age的默认作用域是@protected,即可以在Student类内部和子类中访问
3>第16行:声明了age的get方法,方法名就叫做age,OC建议get方法的名字跟成员变量保持一致。- 表示这是一个动态方法( + 则表示静态方法),动态方法属于对象,静态方法属于类。
4>地18行:方法的方法名是setAge:andHeight:
2.Student.m的实现文件
1 #import "Student.h" 2 3 @implementation Student 4 5 - (int)age { 6 NSLog(@"age..."); 7 return age; 8 } 9 10 - (void) setAge:(int)newAge { 11 NSLog(@"setage..."); 12 age = newAge; 13 } 14 15 - (void) setAge:(int)newAge :(float)newHeight { 16 age = newAge; 17 height = newHeight; 18 } 19 20 @end
第5行和第10行和15行实现了Student.h中声明的方法
在Java或者C#中有一个属性的概念,通常访问成员变量不是直接访问,而是访问这些属性。OC中的属性和Java中的类似,都是通过get/set方法实现的,不过有一点不同的是,OC的get方法通常直接使用变量名。
1 #import <Foundation/Foundation.h> 2 #import "Student.h" 3 int main(int argc, const char * argv[]) 4 { 5 6 @autoreleasepool { 7 8 // insert code here... 9 Student *stu = [[Student alloc]init]; 10 stu.age = 15; 11 NSLog(@"......"); 12 13 int age1 = stu.age; 14 NSLog(@"......"); 15 16 stu->no = 120; 17 [stu setAge:100]; 18 int age = [stu age]; 19 20 NSLog(@"student no=%i,age is=%i,age1=%i",stu->no,age,age1); 21 NSLog(@"Hello, World!"); 22 [stu release]; 23 } 24 return 0; 25 }
1>第9行:创建一个Student类对象,分配空间并初始化
2>第10行获取和设置age的值,等价于调用[stu setAge:15]和int age = [stu age]。点语法的本质是函数调用
2>第16行:公共成员变量no,如果不是公共变量,不能像这样直接访问。注意访问方式:对象->成员变量
通过上面的例子我们可以看出,定义属性的代码都是非常类似的,所以在OC中提供了更简单的方法,OC中可以通过声明@property,同时通过@synthesize自动生成get/set方法。
Student.h文件
1 #import <Foundation/Foundation.h> 2 3 @interface Student : NSObject 4 5 @property NSString *name; 6 @property NSString *birth; 7 @property float grade; 8 @end
Student.m文件
1 #import "Student.h" 2 3 @implementation Student 4 5 @synthesize name; 6 @synthesize birth=_birth; 7 8 @end
main.m文件
1 #import <Foundation/Foundation.h> 2 #import "CateStudent.h" 3 int main(int argc, const char * argv[]) 4 { 5 6 @autoreleasepool { 7 8 // insert code here... 9 Student *stu = [[Student alloc]init]; 10 stu.name=@"zhangsan"; 11 stu.birth=@"1993-09-12"; 12 stu.grade=99; 13 NSLog(@"name=%@ and birth=%@ grade=%f",stu.name,stu.birth,stu.grade); 14 } 15 return 0; 16 }
上面的例子包含了使用属性扩展的三种情况:
1>只声明一个属性a,不使用@synthesize实现(如grade):此时编译器会使用_a作为属性的成员变量(如果没有_a变量,编译器会自动生成一个私有的成员变量_a)
2>声明一个属性a,使用@synthesize实现,但是没有指定使用的成员变量(如name):此时编译器会使用a作为属性的成员变量(如果没有a变量,编译器会自动生成一个私有的成员变量a)
3>声明一个属性a,使用@synthesize实现,指定使用的成员变量(如birth):此时编译器会使用指定的成员变量
其实上面的过程在本质上也是生成对应的get/set方法,如果声明了@property而且在.m文件里自定义了实现方法,就会使用自定义方法。
self关键字
在C++中有一个this指针表示当前对象,在OC中也有一个self关键字表示当前对象或者类本身。
Student.h文件:
1 #import <Foundation/Foundation.h> 2 3 @interface Student : NSObject 4 5 @property NSString *name; 6 @property float age; 7 - (void)setName:(NSString *)name andAge:(int)age; 8 +(void)print; 9 +(void)showMsg; 10 @end
Student.m文件:
1 #import "Student.h" 2 3 @implementation Student 4 5 -(void)setName:(NSString *)name andAge:(int)age{ 6 self.name = name;//调用setName 7 self.age = age;//调用setAge 8 } 9 10 +(void)print{ 11 NSLog(@"......"); 12 } 13 14 +(void)showMsg{ 15 [self print]; 16 } 17 @end
main.m文件:
1 #import <Foundation/Foundation.h> 2 #import "CateStudent.h" 3 int main(int argc, const char * argv[]) 4 { 5 6 @autoreleasepool { 7 8 // insert code here... 9 Student *stu = [[Student alloc]init]; 10 [stu setName:@"zhansan" andAge:12]; 11 NSLog(@"name=%@ and age=%f",stu.name,stu.age); 12 [Student showMsg]; 13 } 14 return 0; 15 }
在这个例子中self可以调用静态方法也可以调用动态方法。但是调用的本质是不一样的,动态方法调用既实例里面的self,是对象的首地址;类方法里面的self,是Class。
构造方法
在对象的创建时往往需要初始化调用init方法,接下来我们看下如何创建init方法:
Student.h文件:
1 #import <Foundation/Foundation.h> 2 3 @interface Student : NSObject 4 5 @property NSString *name; 6 @property float age; 7 -(id)initWithName:(NSString*)name andAge:(int)age; 8 9 +(id)stuWithName:(NSString*)name andAge:(int)age; 10 +(void)print; 11 +(void)showMsg; 12 @end
Student.m文件:
1 import "Student.h" 2 3 @implementation Student 4 5 -(id)initWithName:(NSString*)name andAge:(int)age{ 6 if(self=[super init]){ 7 self.name=name; 8 self.age=age; 9 } 10 return self; 11 } 12 13 +(id)stuWithName:(NSString*)name andAge:(int)age{ 14 //类方法不能直接访问实例方法,但是可以通过创建对象访问实例方法 15 Student *s = [[Student alloc]initWithName:name andAge:age]; 16 return s; 17 } 18 19 +(void)print{ 20 NSLog(@"......"); 21 } 22 +(void)showMsg{ 23 [self print]; 24 } 25 @end
main.m文件:
1 #import <Foundation/Foundation.h> 2 #import "CateStudent.h" 3 int main(int argc, const char * argv[]) 4 { 5 6 @autoreleasepool { 7 8 // insert code here... 9 Student *stu = [[Student alloc]initWithName:@"lisi" andAge:11]; 10 NSLog(@"name=%@ and age=%f",stu.name,stu.age); 11 Student *stu1 = [Student stuWithName:@"wanger" andAge:14]; 12 NSLog(@"name=%@ and age=%f",stu1.name,stu1.age); 13 [Student showMsg]; 14 } 15 return 0; 16 }
description方法
在Java中基本每个类都有一个toString()方法用于打印一个对象的信息,在OC中这个方法叫description,这个方法通常用于调试:
1 #import "Student.h" 2 3 @implementation Student 4 5 -(NSString*)description{ 6 return [NSString stringWithFormat:@"{name:%@,age:%f}",self.name,self.age]; 7 } 8 @end
默认情况下如果我们不重写description方法,输出内容是类名和地址。
总结
1、- 表示对象方法(动态方法),+ 表示类方法(静态方法)
2、.语法的本质是get或者set函数调用
3、静态方法中不能直接调用对象方法,但是可以创建对象后调用此方法