建设部网站有建筑施工分包凌云网站
建设部网站有建筑施工分包,凌云网站,做视频采集网站违法吗,个人网站免备案吗面向对象(上)
5.1 类与对象
类是一种自定义数据结构#xff0c;就像c语言的结构体那样#xff0c;但它的功能比结构体更丰富
类是一种概念#xff0c;而对象才是具体存在的
类的声明和使用
定义类需要两个步骤#xff1a;
接口部分interface,定义该类包含的成员变量和方法实…面向对象(上)5.1 类与对象类是一种自定义数据结构就像c语言的结构体那样但它的功能比结构体更丰富类是一种概念而对象才是具体存在的类的声明和使用定义类需要两个步骤接口部分interface,定义该类包含的成员变量和方法实现部分implementation为该类的方法提供实现这是一个类的声明部分#import Foundation/Foundation.h interface fkperson : NSObject { NSString* _name; int _age; } - (void) setName : (NSString*) name andAge : (int) age; - (void) say : (NSString *) content; - (NSString*) info; (void) foo; endinterface用于声明定义类的接口部分end用于表明定义结束成员变量描述该类的对象的状态数据方法用于描述该类的行为#import fkperson.h implementation fkperson { ...... } - (void) setName : (NSString*) name andAge : (int) age{ ...... } - (void) say : (NSString *) content{ ...... } - (NSString*) info{ ...... } (void) foo{ ...... } end类实现部分的类名必须和类接口部分的类名一致类实现部分也可以声明自己的成员变量但仅可以在当前类内访问类实现部分必须为类声明部分的每个方法提供方法定义对象的产生与使用对象的产生类名 *对象名 [[类名 alloc] init]; Person *p [[Person alloc] init];这其实是两步常被写成一步:为对象分配内存也就是allocinit初始化这个对象当然也可以用自己的方法初始化(将init改写)或者带参数的构造方法Person *p [[Person alloc] initWithName:Alice age:18];对象的使用有两种方式访问对象一种是点语法另一种是消息发送方式p.name Tom; NSString *n p.name; [p setName:Tom]; NSString *n [p name];5.2方法在上一节类中我们发现其中就有方法的身影 简单来说方法其实就是类中的一个函数方法类型符号调用者示例实例方法-对象- (void)run类方法类名 (void)info实例方法实例方法是通过对象调用用-开头类方法通过类名调用用开头#import Foundation/Foundation.h interface fkperson : NSObject { NSString* _name; int _age; } - (void) setName : (NSString*) name andAge : (int) age; - (void) say : (NSString *) content; - (NSString*) info; (void) foo; end[fkperson foo];//调用foo类方法 fkperson* person [[fkperson alloc] init]; [person info];//调用info实例方法并且在实例方法中可以引用类方法但在类方法中不能引用实例方法 (void)foo { NSLog(调用了 FKPerson 的 foo 类方法); // 类方法中不能访问实例变量/实例方法如 self-_name、[self info] 都会报错 } // 实现实例方法 info - (void)info { NSLog(调用了 FKPerson 的 info 实例方法); // 实例方法中可以访问类方法如 [FKPerson foo] [FKPerson foo]; }5.4封装在 Objective-C 中封装的核心落地手段是属性的 Setter赋值方法和 Getter取值方法—— 它们是类对外暴露属性的 “可控接口”既允许外部合法访问数据又能隐藏内部的存储细节和校验逻辑是 “开放封闭原则” 的典型体现Setter控制属性的赋值逻辑实现数据校验、内存管理如 copy/strongGetter控制属性的取值逻辑实现懒加载、数据格式化、只读保护等。基础用法自动生成 自定义实现自动生成interface Person : NSObject // 声明属性编译器自动生成 Setter/Getter property (nonatomic, copy) NSString *name; // 字符串用 copy 避免浅拷贝 property (nonatomic, assign) NSInteger age; // 基本类型用 assign end implementation Person // ARC 下无需手动实现编译器自动生成以下逻辑 // - (NSString *)name { return _name; } // - (void)setName:(NSString *)name { _name [name copy]; } // - (NSInteger)age { return _age; } // - (void)setAge:(NSInteger)age { _age age; } end // 外部通过 Setter/Getter 访问无需关心内部存储 Person *p [[Person alloc] init]; p.name 张三; // 等价于 [p setName:张三] p.age 25; // 等价于 [p setAge:25] NSLog(姓名%年龄%ld, p.name, p.age); // 等价于 [p name]、[p age]自定义生成当自动生成的逻辑无法满足需求时如数据校验可自定义 Setter 或 Getterimplementation Person // 自定义 age 的 Setter校验年龄合法性 - (void)setAge:(NSInteger)age { // 拦截负数、超过150的非法年龄 if (age 0 || age 150) { _age 0; // 重置为合法默认值 NSLog(年龄不合法已自动修正为0); } else { _age age; } } // name 的 Getter 沿用自动生成的即可 end // 测试非法赋值被拦截 p.age 200; // 输出年龄不合法已自动修正为0 NSLog(年龄%ld, p.age); // 结果0区分 “点语法” 和 “实例变量”点语法p.age本质是调用 Setter/Getter会触发校验、懒加载等逻辑直接访问实例变量p-_age跳过 Setter/Getter直接修改内存破坏封装严禁在类外部使用。用readonly修饰属性编译器仅生成 Getter不生成 Setter实现 “只读” 封装5.6 对象创建与初始化在 Objective-C 中对象的创建通常需要两个步骤分配内存和初始化对象。只有经过初始化的对象才能正常使用。5.6.1 对象的创建过程创建对象通常写成下面的形式Person*p[[Person alloc]init];这个语句实际上包含两个步骤allocalloc方法负责为对象在堆内存中分配空间并返回对象的地址。initinit方法用于对对象进行初始化例如给成员变量赋初值。因此对象创建流程可以理解为alloc → 分配内存 init → 初始化对象只有两个步骤都完成后对象才算真正创建成功。5.6.2 自定义初始化方法在很多情况下系统默认的init方法并不能满足需求我们需要自己编写初始化方法来设置对象的初始状态。例如interfaceUser:NSObjectpropertyNSString*name;propertyintage;propertyNSString*address;end实现自定义初始化implementationUser-(instancetype)init{self[superinit];if(self){_name默认名字;_age18;_address北京;}returnself;}end初始化方法通常遵循一个固定模板-(instancetype)init{self[superinit];// 调用父类初始化方法if(self){// 初始化成员变量}returnself;}这样写的好处是如果父类初始化失败返回nil子类也不会继续执行初始化代码。5.6.3 带参数的初始化方法除了默认的init方法还可以定义带参数的初始化方法这样在创建对象时可以直接设置属性值。例如interfaceCar:NSObjectpropertyNSString*brand;propertyNSString*model;propertyNSString*color;-(instancetype)initWithBrand:(NSString*)brand model:(NSString*)model;-(instancetype)initWithBrand:(NSString*)brand model:(NSString*)model color:(NSString*)color;end实现implementationCar-(instancetype)initWithBrand:(NSString*)brand model:(NSString*)model{if(self[superinit]){_brandbrand;_modelmodel;_color黑色;}returnself;}-(instancetype)initWithBrand:(NSString*)brand model:(NSString*)model color:(NSString*)color{if(self[selfinitWithBrand:brand model:model]){_colorcolor;}returnself;}end这种写法的优点是可以减少重复代码提高代码复用性创建对象时更加灵活示例Car*car1[[Car alloc]init];Car*car2[[Car alloc]initWithBrand:奔驰model:ML350];Car*car3[[Car alloc]initWithBrand:宝马model:X5color:黑色];5.7 继承继承是面向对象编程的重要特性之一它可以让一个类获得另一个类的属性和方法从而实现代码复用。在 Objective-C 中继承通过:语法实现interface子类:父类end其中被继承的类称为父类superclass继承父类的类称为子类subclass5.7.1 继承的基本特点继承的主要作用包括代码复用子类可以直接使用父类已有的方法和属性。扩展功能子类可以在父类基础上增加新的功能。层级关系继承可以形成类的层次结构。例如interfaceFruit:NSObjectpropertydoubleweight;-(void)info;end实现implementationFruit-(void)info{NSLog(这是一个水果重量为 %g g,self.weight);}end定义一个子类interfaceApple:FruitendimplementationAppleend创建对象并调用方法Apple*a[[Apple alloc]init];a.weight200;[a info];由于Apple继承自Fruit所以它可以直接使用父类中的weight属性和info方法。5.7.2 Objective-C 的继承规则Objective-C 采用单继承机制即一个类只能有一个父类但可以形成多层继承例如NSObject ↓ Vehicle ↓ Car ↓ SportsCar这种结构称为继承链。5.7.3 方法重写Override子类不仅可以继承父类的方法还可以重新实现父类的方法这称为方法重写。例如父类interfaceBird:NSObject-(void)fly;endimplementationBird-(void)fly{NSLog(小鸟在天空飞翔);}end子类interfaceOstrich:Bird-(void)callSuperMethod;end实现implementationOstrich-(void)fly{NSLog(鸵鸟不会飞只能奔跑);}-(void)callSuperMethod{[superfly];}end说明子类重写了fly方法使用super可以调用父类原来的实现测试Ostrich*o[[Ostrich alloc]init];[o fly];// 调用子类方法[o callSuperMethod];// 调用父类方法