002-OC基础语法
一、关键字:improt与include
1.相同点
improt与include都有文件包含的功能
2.不同点
improt是OC的关键字,而include是C的关键字;二者的最大区别在于improt可以防止重复包含,而include则容易造成重复包含的问题。
二、关键字:NSLog与printf
NSLog是OC的关键字,printf是C的关键字;前者打印输出自动换行,并且打印输出会有时间、日期等信息
三、OC的数据类型
1.OC的数据类型分类
1)基本数据类型:int、float、double、char
2)对象类型:OC的对象类型实际就是C的结构体
3)id类型:泛型指针
4)BOOL类型:本质就是char类型,可以当成整数来用(YES = 1, NO = 0)
5)SEL类型:方法包装
6)block类型:本质就是指向函数的指针,另外block弥补了指向函数的指针不能直接保存一个函数体
2.数据类型的特征
1)可作为参数传递
2)可作为函数的返回值
3)可以声明成变量
3.数据类型的作用
OC中的这些数据类型也是为了更加合理地分配内存空间
4.重点讲解
1)SEL类型
我们声明对象的方法,被包装成一个SEL类型的变量(SEL s = @selector(方法名))放在对象方法列表中,我们在调用对象方法时,实际上是对象里的isa指针指向该方法列表中SEL变量,通过这个变量指针地址去查找相应的方法。
1 // Person.h文件 2 #import <Foundation/Foundation.h> 3 4 @interface Person : NSObject 5 6 #pragma mark - 成员属性 7 @property (nonatomic, copy) NSString *name; 8 @property (nonatomic, assign) int age; 9 @property (nonatomic, copy) NSString *sex; 10 11 #pragma mark - 方法 12 - (void)name:(NSString *)name age:(int)age sex:(NSString *)sex; 13 14 @end 15 16 17 // Person.m文件 18 #import "Person.h" 19 20 @implementation Person 21 22 #pragma mark - 方法 23 - (void)name:(NSString *)name age:(int)age sex:(NSString *)sex 24 { 25 NSLog(@"name = %@, age = %d, sex = %@", name, age, sex); 26 } 27 28 @end 29 30 31 // ViewController.m文件 32 #import "ViewController.h" 33 #import "Person.h" 34 35 @implementation ViewController 36 37 - (void)viewDidLoad { 38 [super viewDidLoad]; 39 40 Person *p = [[Person alloc] init]; 41 p.name = @"Frank"; 42 p.age = 25; 43 p.sex = @"M"; 44 // 将方法包装成SEL类型 45 // SEL abc = @selector(name:age:sex:); 46 // 通过performSelector:方法调用SEL类型的对象方法 47 [p performSelector:@selector(name:age:sex:)]; 48 } 49 50 @end
2)block类型
实例一:block作为函数参数传递
1 // Calculate.h文件 2 #import <Foundation/Foundation.h> 3 4 #pragma mark - block类型的声明 5 typedef int(^CalculateBlock)(int a, int b); 6 7 @interface Calculate : NSObject 8 9 #pragma mark - 将block类型作为函数参数传递 10 - (int)calculateWithNumber1:(int)num1 number2:(int)num2 calculateBlock:(CalculateBlock)calculate; 11 12 @end 13 14 15 // Calculate.m文件 16 #import "Calculate.h" 17 18 @implementation Calculate 19 20 #pragma mark - block作为函数参数传递,其调用在函数调用的时候进行 21 - (int)calculateWithNumber1:(int)num1 number2:(int)num2 calculateBlock:(CalculateBlock)calculate 22 { 23 return calculate(num1, num2); 24 } 25 26 @end 27 28 29 // ViewController.m文件 30 #import "ViewController.h" 31 #import "Calculate.h" 32 33 @implementation ViewController 34 35 - (void)viewDidLoad { 36 [super viewDidLoad]; 37 38 Calculate *cal = [[Calculate alloc] init]; 39 int sum = [cal calculateWithNumber1:20 number2:30 calculateBlock:^int(int a, int b) { 40 return a + b; 41 }]; 42 NSLog(@"sum = %d", sum); 43 } 44 45 @end
实例二:block作为成员变量
1 // Calculate.h文件 2 #import <Foundation/Foundation.h> 3 4 #pragma mark - block类型的声明 5 typedef int(^CalculateBlock)(int a, int b); 6 7 @interface Calculate : NSObject 8 9 #pragma mark - 将block类型作为成员属性 10 @property (nonatomic, copy) CalculateBlock cb; 11 12 #pragma mark - 方法 13 - (void)calculateWithNum1:(int)num1 num2:(int)num2; 14 15 @end 16 17 18 // Calculate.m文件 19 #import "Calculate.h" 20 21 @implementation Calculate 22 23 #pragma mark - 方法实现 24 - (void)calculateWithNum1:(int)num1 num2:(int)num2 25 { 26 // 判断block作为成员变量,是否被赋值 27 if (self.cb) { 28 // 如果被赋值,就被调用 29 self.cb(num1, num2); 30 } 31 } 32 33 @end 34 35 36 // ViewController.m文件 37 #import "ViewController.h" 38 #import "Calculate.h" 39 40 @implementation ViewController 41 42 - (void)viewDidLoad { 43 [super viewDidLoad]; 44 45 Calculate *cal = [[Calculate alloc] init]; 46 // 给cal对象的block类型成员变量cb赋值 -- 也就是block的实现 47 cal.cb = ^ int (int a, int b) { 48 int sum = a + b; 49 return sum; 50 }; 51 52 // 调用cal方法 53 [cal calculateWithNum1:20 num2:30]; 54 } 55 56 @end
实例三:主动调用block,block修改外部变量的值
1 // ViewController.m文件 2 #import "ViewController.h" 3 4 #pragma mark - block类型的声明 5 typedef void(^BoolBlock)(BOOL); 6 7 @implementation ViewController 8 9 - (void)viewDidLoad { 10 [super viewDidLoad]; 11 12 // block内部想要改变外部变量的值,则必须使用__block修饰该变量 13 __block int i = 1024; 14 BoolBlock cb = ^(BOOL bv) { 15 if (bv) { 16 // block内部修改外部变量的值 17 i++; 18 } 19 }; 20 BOOL a = YES; 21 22 // 主动调用一下block 23 cb(a); 24 } 25 26 @end
关于block,需要注意一下几点:
a.block做成员变量,参数必须用copy,copy会将block的生命周期从栈转移到堆空间,其生命周期就会交给程序员自己管理,不会出现block被提前释放,也就不会造成block野指针错误
b.block作为参数时,为防止循环引用,必须放在函数尾部
c.默认情况下,任何的block都是放在栈里边,随时都可能会被回收,block没有使用retain,理由是retain只是计数器加1,内存地址不会改变,因而不能将block从栈里边放到堆里
d.MRC模式下用__block去修饰block代码块内部需要引用的对象,在ARC模式下用__weak去修饰block内部引用的对象,这样可防止由于循环引用造成的内存泄露
e.block内部修改外部变量的值,必须使用__block修饰该变量,一般情况下我们不建议在block内部去修改外部变量的值
四、Category(类别、分类)
1.Category的基本要点
1)分类只是扩展方法,不可以扩展成员变量;但是在分类中是可以直接访问原来类中.h文件声明的所有方法和所有成员变量
2)分类可以在不获悉、不改变原来类的的同时,可以为原来类扩展一些方法;但是分类只可以扩展原来类的方法,不可以修改和删除原来类的方法
3)在分类中重写原类中的方法,会覆盖原来类的方法,并且该重写后的方法只会在分类中有效,对于原来的类是没有影响
4)在同一个原有类的多个分类中如果出现了相同的方法,系统会根据编译顺序来决定调用的是哪一个分类中的扩展方法
5)分类是可以被继承的,在父类中导入分类的头文件,那么在其子类中也是可以访问分类中的扩展方法
2.Category的优点
1)将类的实现分散到多个不同的文件或是不同的框架中
2)可以向对象添加非正式协议
3)创建私有方法的前向引用
3.Category的创建步骤



1 // NSString+LD.h文件 2 #import <Foundation/Foundation.h> 3 4 @interface NSString (LD) 5 6 #pragma mark - 统计字符串中0-9的个数 7 + (int)numberCountOfString:(NSString *)string; 8 #pragma mark - 统计字符串中0-9的个数 9 - (int)numberCount; 10 11 @end 12 13 14 // NSString+LD.m文件 15 #import "NSString+LD.h" 16 17 @implementation NSString (LD) 18 19 #pragma mark - 统计字符串中0-9的个数 20 + (int)numberCountOfString:(NSString *)string 21 { 22 return [string numberCount]; 23 } 24 25 #pragma mark - 统计字符串中0-9的个数 26 - (int)numberCount 27 { 28 int count = 0; 29 for (int i = 0; i < self.length; i++) { 30 unichar c = [self characterAtIndex:i]; 31 // 字符都是以ASCII码存储的 32 if (c >= '0' && c <= '9') { 33 count++; 34 } 35 } 36 return count; 37 } 38 39 @end 40 41 42 // ViewController.m文件 43 #import "ViewController.h" 44 #import "NSString+LD.h" // 导入分类头文件 45 46 @implementation ViewController 47 48 - (void)viewDidLoad { 49 [super viewDidLoad]; 50 51 // 调分类中的类方法 52 int num1 = [NSString numberCountOfString:@"34ty6iui2"]; 53 NSLog(@"num1 = %d", num1); 54 55 // 调用分类中的对象方法 56 NSString *string = @"34ty6iui2"; 57 int num2 = [string numberCount]; 58 NSLog(@"num2 = %d", num2); 59 } 60 61 @end
4.补充说明
分类中不可以扩展原来类的成员变量也不是绝对的。比如在分类中引进运行(runtime),是可以扩展成员属性的。因为分类扩展的成员变量是不能生成get和set方法的,那么我们可以在.m文件中引进运行时技术,动态地给成员变量添加两个方法(get和set方法)
1 // Person.h文件 2 #import <Foundation/Foundation.h> 3 4 @interface Person : NSObject 5 6 @property (nonatomic, copy) NSString *name; 7 @property (nonatomic, assign) int age; 8 9 @end 10 11 12 // Person.m文件 13 #import "Person.h" 14 15 @implementation Person 16 17 @end 18 19 20 // Person+LD.h文件 21 #import "Person.h" 22 23 @interface Person (LD) 24 25 #pragma mark - 分类中扩展的成员属性 26 @property (nonatomic, assign) double height; 27 28 @end 29 30 31 // Person+LD.m文件 32 #import "Person+LD.h" 33 #import <objc/message.h> // 导入运行时头文件 34 35 @implementation Person (LD) 36 37 // 静态变量 38 static double HeightKey; 39 40 #pragma mark - set方法 41 - (void)setHeight:(double)height 42 { 43 objc_setAssociatedObject(self, &HeightKey, @(height), OBJC_ASSOCIATION_ASSIGN); 44 } 45 46 #pragma mark - get方法 47 - (double)height 48 { 49 return [objc_getAssociatedObject(self, &HeightKey) doubleValue]; 50 } 51 52 @end 53 54 55 // ViewController.m文件 56 #import "ViewController.h" 57 #import "Person+LD.h" // 导入分类头文件 58 59 @implementation ViewController 60 61 - (void)viewDidLoad { 62 [super viewDidLoad]; 63 64 // 调用 65 Person *p = [[Person alloc] init]; 66 p.name = @"Frank"; 67 p.age = 25; 68 p.height = 110.5; // 分类中扩展的成员属性 69 NSLog(@"height = %.2f", p.height); 70 } 71 72 @end
5.总结
分类是对一些系统的类进行功能的补充。就好比是一个产品当你发现它的缺陷和一些不足时,你就会想着去完善和补充,但是产品的缘由功能都是存在的
五、Protocol(协议)
1.Protocol的基本要点
1)协议方法的声明部分在协议文件中
2)协议方法的实现部分在遵循该协议的类文件中
3)协议中被关键字@required修饰的协议方法必须在遵循该协议类中去实现,协议中被关键字@optional修饰的协议方法可以选择实现
4)对于必须实现的协议方法,我们在调用的时候可以随意调用;但是对于可选择实现的协议方法,我们必须先确定已被实现,方可调用,否则会造成程序异常
5)所有的协议都是遵循基协议NSObject
6)父类遵循的协议,同样会被继承父类的子类所遵循;但是子类如果不自己实现该协议方法,那么利用该子类调用该协议方法时,其本质还是相当于父类在调用
7)协议中是不可以声明成员变量的
8)判断遵循协议类是否实现某个协议方法:performSelector:@selector(协议方法)
2.Protocol的创建步骤



3.在实际开发中的情况
实例一:单独创建一个协议文件
1 // LDFrankDelegate.h文件 2 #import <Foundation/Foundation.h> 3 4 @protocol LDFrankDelegate <NSObject> 5 6 #pragma mark - 协议方法的声明部分 7 // 必须实现的协议方法(霸王条款) 8 @required 9 - (void)eat; 10 - (void)drink; 11 12 // 可以选择实现的方法 13 @optional 14 - (void)gamble; 15 - (void)walk; 16 17 @end 18 19 20 // Person.h文件 21 #import <Foundation/Foundation.h> 22 #import "LDFrankDelegate.h" // 导入协议文件 23 24 @interface Person : NSObject<LDFrankDelegate> // 遵循协议 25 26 @end 27 28 29 // Person.m文件 30 #import "Person.h" 31 32 @implementation Person 33 34 #pragma mark - 协议方法的实现部分 35 // 必须实现以下协议方法 36 - (void)eat 37 { 38 NSLog(@"eat"); 39 } 40 - (void)drink 41 { 42 NSLog(@"drink"); 43 } 44 45 // 可以选择实现以下协议方法 46 - (void)gamble 47 { 48 NSLog(@"gamble"); 49 } 50 51 @end 52 53 54 // ViewController.m文件 55 #import "ViewController.h" 56 #import "Person.h" 57 58 @implementation ViewController 59 60 - (void)viewDidLoad { 61 [super viewDidLoad]; 62 63 Person *p = [[Person alloc] init]; 64 // 必须实现的协议方法调用 65 [p eat]; 66 [p drink]; 67 68 // 可实现的协议方法调用 69 // 必须先判断该协议方法是否被实现 70 if ([p performSelector:@selector(gamble)]) { 71 [p gamble]; 72 } 73 if ([p performSelector:@selector(walk)]) { 74 [p walk]; 75 } 76 } 77 78 @end
实例二:直接将协议文件写入遵循该协议文件中
1 // Person.h文件 2 #import <Foundation/Foundation.h> 3 4 #pragma mark - 协议的声明 5 @protocol LDFrankDelegate <NSObject> 6 7 #pragma mark - 协议方法的声明部分 8 // 必须实现的协议方法(霸王条款) 9 @required 10 - (void)eat; 11 - (void)drink; 12 13 // 可以选择实现的方法 14 @optional 15 - (void)gamble; 16 - (void)walk; 17 18 @end 19 20 @interface Person : NSObject<LDFrankDelegate> // 遵循协议 21 22 @end 23 24 25 // Person.m文件 26 #import "Person.h" 27 28 @implementation Person 29 30 #pragma mark - 协议方法的实现部分 31 // 必须实现以下协议方法 32 - (void)eat 33 { 34 NSLog(@"eat"); 35 } 36 - (void)drink 37 { 38 NSLog(@"drink"); 39 } 40 41 // 可以选择实现以下协议方法 42 - (void)gamble 43 { 44 NSLog(@"gamble"); 45 } 46 47 @end
4.总结
Protocol只是定义一些接口,是定义行为而不管谁去实现,是一种不负责任行为。就好比在产品外包中,外发公司只需要拿到功能完善的产品,而不去理睬功能实现的过程。
六、继承
1.成员变量的访问属性
1)private:私有成员属性,不能被外部函数访问,也不能被子类所继承
2)protected:保护成员属性,不能被外部函数访问 ,但是可被子类继承
3)public:公有成员属性,可以被外部函数访问,也可以被子类继承
4)OC中,所有的方法都是公有的
2.关于继承的几个要点
1)OC中的NSObject是大部分类的父类,我们称之为基类或是根类,只有当继承自NSObject这个基类,才有创建对象的能力
2)子类可从父类继承方法,但有时父类的方法不适合子类,子类就可写一个自己的同名方法,覆盖掉父类的同名方法,叫做重写。重写时,在子类的.h中不必重新声明,直接在.m中写实现即可
3)子类可以创建自己的独有方法,该独有方法必须在子类中有完整的声明和实现;子类同时也可以创建自己的成员属性。子类在原有继承基础上,创建自己独有的成员属性和方法,叫做派生
4)父类指针可以指向子类
3.继承的好处
1)创建大量的相似类的时候,可以先创建一个父类,父类中写一些公有的特性,使这些相似的类继承父类,可以节省工作量
2)使用框架中的类,或是已经写好的类,继承该类,生成一个派生类,比原类更好用(NSString、NSArray、NSDictionary都是不能够被继承的)
4.继承的创建步骤


5.实际开发中的问题
1 // Person.h文件 2 #import <Foundation/Foundation.h> 3 4 @interface Person : NSObject 5 { 6 // 公有的 7 @public 8 NSString *_name; 9 10 // 受保护的 11 @protected 12 NSInteger _age; 13 14 // 私有的 15 @private 16 NSInteger _money; 17 } 18 19 @property (nonatomic, copy) NSString *name; 20 @property (nonatomic, assign) NSInteger age; 21 @property (nonatomic, assign) NSInteger money; 22 23 #pragma mark - 父类的方法的声明 24 - (void)eat; 25 - (void)drink; 26 27 @end 28 29 30 // Person.m文件 31 #import "Person.h" 32 33 @implementation Person 34 35 #pragma mark - 父类的方法的实现 36 - (void)eat 37 { 38 NSLog(@"Person eat"); 39 } 40 - (void)drink 41 { 42 NSLog(@"Person drink"); 43 } 44 45 @end 46 47 48 // Boy.h文件 49 #import "Person.h" 50 51 @interface Boy : Person 52 53 #pragma mark - 子类独有的成员属性(派生) 54 @property (nonatomic, copy) NSString *habit; 55 56 #pragma mark - 子类独有的方法的声明(派生) 57 - (void)test; 58 59 @end 60 61 62 // Boy.m文件 63 #import "Boy.h" 64 65 @implementation Boy 66 67 #pragma mark - 子类独有方法的实现 68 - (void)test 69 { 70 // 父类中public和protected修饰的成员属性在子类中可以直接访问 71 _name = @"Frank"; 72 _age = 25; 73 74 // 父类中private修饰的成员属性在子类中不可以直接访问,只能通过父类的方法去访问 75 // _money = 50000000; // 这个就会报错 76 self.money = 50000000; 77 [self setMoney:50000000]; 78 79 NSLog(@"name = %@, age = %ld, money = %ld", _name, _age, [self money]); 80 } 81 82 #pragma mark - 子类重写父类的方法 83 - (void)eat 84 { 85 NSLog(@"男孩都喜欢吃好吃的"); 86 } 87 88 @end 89 90 91 // ViewController.m文件 92 #import "ViewController.h" 93 #import "Boy.h" // 导入子类的头文件 94 95 @implementation ViewController 96 97 - (void)viewDidLoad { 98 [super viewDidLoad]; 99 100 // 父类的指针可以指向子类 101 Person *p = [[Boy alloc] init]; 102 103 // 父类指针指向子类,调用的方法如果是子类的重写方法,那么其调用的还是子类的方法 104 [p eat]; 105 106 // 父类指针指向子类,不可以通过父类指针调用子类的派生方法 107 // [p test]; // 这个会报错 108 } 109 110 @end
七、多态
1.概念
对态就是给不同的对象发送相同的消息,得到的反应结果是不一样的
2.实现多态的条件
1)必须有继承关系:实现多态的对象必须是满足继承关系的对象
2)必须有重写父类的方法
3)必须有父类指针指向子类的对象
3.多态在实际开发中的应用
总结:响应消息,不看指针,看对象
1 // Animal.h文件 2 #import <Foundation/Foundation.h> 3 4 @interface Animal : NSObject 5 6 #pragma mark - 父类方法的声明 7 - (void)beated; 8 9 @end 10 11 12 // Animal.m文件 13 #import "Animal.h" 14 15 @implementation Animal 16 17 #pragma mark - 父类方法的实现 18 - (void)beated 19 { 20 NSLog(@"父类被打, 不知道怎么反应!"); 21 } 22 23 @end 24 25 26 // Cat.h文件 27 #import "Animal.h" 28 29 @interface Cat : Animal 30 31 @end 32 33 34 // Cat.m文件 35 #import "Cat.h" 36 37 @implementation Cat 38 39 #pragma mark - 重写父类方法 40 - (void)beated 41 { 42 NSLog(@"猫被打:miao, miao, 跑到树上!"); 43 } 44 45 @end 46 47 48 // Tiger.h文件 49 #import "Animal.h" 50 51 @interface Tiger : Animal 52 53 @end 54 55 56 // Tiger.m文件 57 #import "Tiger.h" 58 59 @implementation Tiger 60 61 #pragma mark - 重写父类方法 62 - (void)beated 63 { 64 NSLog(@"老虎被打:Come on, I am hungry!"); 65 } 66 67 @end 68 69 70 // Wolf.h文件 71 #import "Animal.h" 72 73 @interface Wolf : Animal 74 75 @end 76 77 78 // Wolf.m文件 79 #import "Wolf.h" 80 81 @implementation Wolf 82 83 #pragma mark - 重写父类方法 84 - (void)beated 85 { 86 NSLog(@"狼被打: 我还会回来的!"); 87 } 88 89 @end 90 91 92 // Person.h文件 93 #import <Foundation/Foundation.h> 94 #import "Animal.h" 95 96 @interface Person : NSObject 97 98 #pragma mark - Animal 可以接受所有的子类 99 // 参数:animal,可以接受所有继承自Animal类的子类对象 100 - (void)beat:(Animal *)animal; 101 102 @end 103 104 105 // Person.m文件 106 #import "Person.h" 107 108 @implementation Person 109 110 #pragma mark - 使用了父类的指针,作为形参 111 - (void)beat:(Animal *)animal 112 { 113 NSLog(@"%@ 被打啦", NSStringFromClass([animal class])); 114 [animal beated]; 115 } 116 117 @end 118 119 120 // ViewController.m文件 121 #import "ViewController.h" 122 #import "Person.h" 123 #import "Cat.h" 124 #import "Tiger.h" 125 #import "Wolf.h" 126 127 @implementation ViewController 128 129 - (void)viewDidLoad { 130 [super viewDidLoad]; 131 132 133 Person *p = [[Person alloc] init]; 134 135 // 初始化子类 136 Cat *cat = [[Cat alloc] init]; 137 Tiger *tiger = [[Tiger alloc] init]; 138 Wolf *wolf = [[Wolf alloc] init]; 139 140 // 通过父类指针调用子类重写的方法 -- 得到不同的反应结果 141 [p beat:cat]; 142 [p beat:tiger]; 143 [p beat:wolf]; 144 } 145 146 @end
八、封装
1.类是对数据和功能的封装。其中成员属性就是读对数据的封装,而方法就是对功能的封装
2.在OC语言中,使用@interface和@implementation来处理类
3.@interface就好像暴露在外面的时钟表面,像外界提供展示以及接口。
4.@implementation就好像隐藏在时钟内部的构造实现,把具体的实现封装了起来。
九、self关键字与点语法
1.self关键字
1)self是一个指针,谁调用了当前方法,self就指向谁(出现在对象方法中,就代表着当前对象,出现在类方法中,就代表着当前类)
2)self的用途:
a.可以利用 self->成员变量名 访问当前对象内部的成员变量(仅在对象方法中)
b.[self 方法名];可以调用其他的对象方法或者是类方法
2.点语法
1)为什么要使用点语法
a.为了方便别的程序员转到OC上面来(C++/Java/C#都是使用的点语法)
b.为了让程序设计简单化,隐藏一些内存管理、多线程、同步、枷锁的细节
2)点语法的调用
a.点语法与set方法:
person.name = @"Frank"; // 点语法赋值
[person setName:@"Frank"]; // set方法
b.点语法与get方法:
person.name; // 点语法取值
[person name]; // get方法
3)点语法的条件
a.对象调用点语法,对象必须实现set和get方法
b.使用点语法的set方法,只能够带有一个参数
十、对象之间的关系
1.匿名对象
1 // Book.h文件 2 #import <Foundation/Foundation.h> 3 4 @interface Book : NSObject 5 6 @end 7 8 9 // Book.m文件 10 #import "Book.h" 11 12 @implementation Book 13 14 @end 15 16 17 // Person.h文件 18 #import <Foundation/Foundation.h> 19 #import "Book.h" 20 21 @interface Person : NSObject 22 23 #pragma mark - 成员属性 24 @property (nonatomic, copy) NSString *name; 25 26 #pragma mark - 方法声明 27 - (void)readBook:(Book *)book; 28 29 @end 30 31 32 // Person.m文件 33 #import "Person.h" 34 35 @implementation Person 36 37 #pragma mark - 方法实现 38 - (void)readBook:(Book *)book 39 { 40 NSLog(@"读书"); 41 } 42 43 @end 44 45 46 // ViewController.m文件 47 #import "ViewController.h" 48 #import "Person.h" 49 #import "Book.h" 50 51 @implementation ViewController 52 53 - (void)viewDidLoad { 54 [super viewDidLoad]; 55 56 // [类名 new]; // 创建一个匿名对象 57 [[Person new] readBook:[Book new]]; 58 } 59 60 @end
匿名对象的作用:
1)当调用使用次数很少的方法的时候,就直接使用匿名对象调用
2)匿名对象可以作为参数传递,当不需要给传递的对象的成员变量赋值的时候,就使用匿名对象作为参数传递
2.依赖关系
1)A对象作为B对象的局部变量或是方法形参,则B依赖于A,这时我们讲AB对象之间是一种依赖关系
2)在面向对象编程中:
耦合度:指的是修改一个对象而对另一个对象的影响程度
低耦合:指的是修改一个对象对其他对象的影响程度比较小
高内聚:一个对象仅仅只做与自己相关的事情
3.关联关系
简单地讲,就是指A对象为B对象的成员变量,我们就说A对象与B对象之间存在一种关联关系
关联关系的耦合度要高于依赖关系
十一、类与对象
1.类
1)类的本质:类其实也是个对象,只不过是类对象
1 // Person.h文件 2 #import <Foundation/Foundation.h> 3 4 @interface Person : NSObject 5 6 #pragma mark - 成员属性 7 @property (nonatomic, copy) NSString *name; 8 @property (nonatomic, assign) NSInteger age; 9 10 @end 11 12 13 // Person.m文件 14 #import "Person.h" 15 16 @implementation Person 17 18 @end 19 20 21 // Viewcontroller.m文件 22 #import "ViewController.h" 23 #import "Person.h" // 导入头文件 24 25 @implementation ViewController 26 27 - (void)viewDidLoad { 28 [super viewDidLoad]; 29 30 // 1.利用类去创建类的对象 31 Person *p = [[Person alloc] init]; 32 p.name = @"Dave"; 33 p.age = 10; 34 35 // 2.利用类对象去创建类的对象 36 Class c = [p class]; // 内存中的类对象,我们也可以使用这个类对象去调用类方法 37 Person *p1 = [[c new] init]; 38 p1.name = @"Frank"; 39 p1.age = 25; 40 } 41 42 @end
2)类的加载
两大方法:+ (void)load; + (void)initialize;
a.当程序启动时,就会加载项目中所有的类和分类,而且加载会调用load方法,该方法只会调用一次
b.当程序第一次使用某个类时,就会调用该类的initialize方法
c.类加载的顺序:先加载父类,再加载子类(先调用父类的load方法,后调用子类的load方法);对于分类,先加载原来类,再加载分类
d.第一次使用子类:先初始化父类,再初始化子类(先调用父类的initialize方法,后调用子类的initialize方法)
2.对象
OC的对象实质就是C语言中的结构体
十二、description方法
1.调用
打印输出对象时调用该方法,我们一般可以在这里返回对象的属性输出
2.方法
类方法:+ (NSString *)description;
对象方法:- (NSString *)description;
(未完待续......)

浙公网安备 33010602011771号