Objective-C基础笔记三

来源:互联网 发布:mac 远程登录 编辑:程序博客网 时间:2024/05/28 15:14

封装


本小节知识:

  1. 面向对象三大特性
  2. 什么是封装
  3. 为什么要进行封装?
  4. 封装的好处和原则

1.面向对象三大特性

  • 封装性
  • 继承性
  • 多态性

2.什么是封装

  • 封装就是隐藏实现细节,仅对外公开接口;
  • 类是数据与功能的封装,数据就是成员变量,功能就类方法或对象方法;
  • 对数据的封装,也就是对成员变量的封装 。

  • 注意:成员变量都需要封装起来。

  • 原则:将不需要对外提供的内容都隐藏起来,把属性都隐藏,提供公共的方法对其访问


3.为什么要进行封装?

  • 如果希望成员变量能够被外界访问,则必须是@public的,也就是公开的,但我们不能控制外界如何赋值, 外界有可能赋值一些没用的数据

  • 不封装的缺点:当一个类把自己的成员变量暴露给外部的时候,那么该类就失去对该成员变量的管理权,别人可以任意的修改你的成员变量。


4.封装的好处

  • 将变化隔离;
  • 提高安全性;
  • 不可被外部任意修改;降低了数据被误用的可能性;
  • 提高代码的灵活性。

问题:封装的规范?

  • 规范: 一般情况下不会对外直接暴露成员变量, 都会提供一些共有的方法进行赋值

1.setter方法

  • 作用:用来设置成员变量,可以在方法里面过滤掉一些不合理的值

  • 命名规范:

    1. 必须是对象方法2. 返回值类型为void3. 方法名必须以set开头,而且后面跟上成员变量名去掉”_” 首字母必须大写4. 必须提供一个参数,参数类型必须与所对应的成员变量的类型一致5. 形参名称和成员变量去掉下划线相同
  • 举例:

    如:如果成员变量为int _age 那么与之对应seter方法为-(void) setAge: (int) age;
  • 优点:

    1. 不让数据暴露在外,保证了数据的安全性2. 对设置的数据进行过滤

2.getter方法

  • 作用:为调用者返回对象内部的成员变量的值
  • 命名规范:
    objectivec
    <ol><li>必须是对象方法</li>
    <li>必须有返回值,返回值的类型和成员变量的类型一致</li>
    <li>方法名必须是成员变量去掉下划线</li>
    <li>一定是没有参数的
  • 举例:

    如:如果成员变量为int _age 那么与之对应geter方法为- (int) age;
  • 优点:可以让我们在使用getter方法获取数据之前,对数据进行加工;


3.getter/setter方法注意

  • 在实际的开发中,不一定set和get方法都会提��供,如果内部的成员变量,比如学生的学号或计算出来的数据。这样的数据只允许外界读取,但是不允许修改的情况,则通常只提��供get方法而不��提供set方法

  • 成员变量名的命名以下划线开头,get方法名不需要带下划线

  • 成员变量名使用下划线开头有两个好处

    • 与get方法的方法名区分开来
    • 可以和一些其他的局部变量区分开来,下划线开头的变量,通常都是类的成员变量。当我看到以下划线开头变量,那么他一定是成员变量

问题:成员变量以下划线开头有什么好处?

  • 用于和局部变量/全局变量/形参区分
  • 方便程序编码, 提高编码效率

自定义代码段

本小节知识点:

  1. 如何自定义代码片段
  2. 如何导入代码片段

1.如何自定义代码片段

  • 将代码拖拽到code区域
  • 配置快捷键等信息
  • 使用自定义代码段快捷键

2.如何导入代码片段

  • 将下载好的代码片段拷贝到:`

    /Users/你的用户名/Library/Developer/Xcode/UserData/CodeSnippets文件夹里


问题:自定义快捷键的格式是什么?在代码库中的设置是怎么样的?

  • 自定义快捷键的格式 <#name#>

点语法(重点)


本小节知识点:

  1. 【掌握】点语法的本质
  2. 【掌握】点语法注意
  3. 【掌握】点语法基本使用

1.点语法的本质

  • 其实点语法的本质还是方法调用
  • 当使用点语法时,编译器会自动展开成相应的setter/getter方法;
  • 当点语法使用在 “=“赋值符号左侧的时候,点语法会被展开为setter方法的调用;
  • 其他情况(等号右侧、直接使用)为点语法展开为getter方法的调用

2.点语法注意

  • 点语法的本质是方法的调用,而不是访问成员变量,当使用点语法时,编译器会自动展开成相应的方法调用。
  • 切记点语法的本质是转换成相应的对setter和getter方法调用,如果没有set和get方法,则不能使用点语法。
  • 不要在getter 与 setter方法中使用本属性的点语法来点自己,造成死循环
- (void) setAge:(int)age {    // 下面的代码会引发死循环    self.age = age;    //self.gae 编译器展开后 [self setAge:age]}
- (int) age {    // 下面的代码会引发死循环    return self.age;    //self.age 编译器展开后 [self age]}

3.点语法基本使用

  • 点语法是一个编译器的特性, 会在程序翻译成二进制的时候将.语法自动转换为setter和getter方法
  • 如果点语法在=号的左边, 那么编译器会自动转换为setter方法
  • 如果点语法在=号的右边, 或者没有等号, 那么编译器就会自动转换为getter方法
  • 点语法一般用于给成员变量赋值, 如果不是给成员变量赋值一般情况下不建议使用, 但是也可以使用

Self关键字


本小节知识点:

  1. 类方法中的self
  2. 对象方法中的self
  3. 全局变量成员变量局部变量
  4. self总结
  5. self使用注意

  • OC提��供了两个保留字self和super
    • OC语言中的self,就相当于C++、Java中的this指针。

1.类方法中的self

  • 在整个程序运行过程中,一个类有且仅有一个类对象
  • 通过类名调用方法就是给这个类对象发送消息。
  • 类方法的self就是这个类对象
  • 在类方法中可以通过self来调用其他的类方法
  • 不能在类方法中去调用对象方法或成员变量,因为对象方法与成员变量都是属于具体的实例对象的。

2.对象方法中的self

  • 在整个程序运行过程中,对象可以有0个或多个
  • 通过对象调用方法就是给这个对象发送消息
  • 对象方法中self就是调用这个方法的当前对象。
  • 在对象方法中,可以通过self来调用本对象上的其他方法
  • 在对象方法中,可以通过self来访问成员变量

3.全局变量成员变量局部变量

  • 全局变量:只要是有声明它的地方都能使用
  • 成员变量:只能在本类和其子类的对象方法中使用
  • 局部变量:只能在本函数或方法中使用
  • 从作用域的范围来看:全局变量 > 成员变量 > 局部变量
  • 当不同的作用域中出现了同名的变量,内部作用域的变量覆盖外部作用域变量,所以同名变量的覆盖顺序为:局部变量覆盖成员变量,成员变量覆盖全局变量
  • 可以通过self->成员变量名的方式,区分成员变量和局部变量同名的情况

4.self总结

  • 谁调用self所在的方法,那么self就是谁
  • self在类方法中,就是这个类的类对象,全局只有一个,可通过self调用本类中的其他类方法,但是不能通过self来调用对象方法或访问成员变量
  • self在对象方法中,就是调用这个方法的那个对象, 可以通过self调用本类中其他的对象方法,访问成员变量,但不能通过self调用本类的类方法。
  • 通过self调用方法的格式:[self 方法名];
  • 通过self访问成员变量格式:self->成员变量名

5.self使用注意

  • 同时有对象方法和类方法存在的时候,self不会调错
  • self只能在方法中使用;不要使用self来调用函数,也不可以在函数内部使用self;
  • 使用self调用本方法,导致死循环调用。

问题1:什么是成员变量?什么是对象方法?什么是类方法?

  • 成员变量:成员变量是一个实例对象的具体状态特征,并且这些状态特征是可以改变的,如张三的年龄,身高,体重等

  • 对象方法:一个实例对象的行为,比如张三具有吃的行为,张三做出这样行为的时候,有可能会影响,自身的某些状态特征,比如张三吃可能会增加张三体重和身高。

  • 类方法:类方法是某个类的行为,可以直接通过类名调用;如果在类方法中需要使用某些数据,必须通过参数传入;它不能访问成员变量。


继承的基本概念

本小节知识点:

  1. 继承基本概念
  2. OC中的继承关系
  3. OC中如何实现继承

1.继承基本概念

  • 现实生活中的继承;
  • 交通工具类是一个基类(也称做父类),通常情况下所有交通工具所共同具备的特性,如速度与额定载人的数量;
  • 飞机类和汽车类的特性是由在交通工具类原有特性基础上增加而来的,那么飞机类和汽车类就是交通工具类的派生类(也称做子类)。以此类推,层层递增, 这种子类获得父类特性的概念就是继承。

2.OC中的继承关系

  • B类继承A类,那么B类将拥有A类的所有属性和方法,此时我们说A类是B类的父类,B类是A类的子类

  • C类继承B类,那么C类将拥有B类中的所有属性和方法,包括B类从A类中继承过来的属性和方法,此时我们说B类是C类的父类,C类是B类的子类

  • 注意:

    • 基类的私有属性能被继承,不能在子类中访问。
    • OC中的继承是单继承:也就是说一个类只能一个父类,不能继承多个父类
    • 子类与父类的关系也称为isA(是一个)关系,我们说 子类isA父类,也就是子类是一个父类,比如狗类继承动物类,那么我们说狗isA动物,也就是狗是一个动物。在如汽车继承交通工具,那么们说汽车isA交工工具,也就是汽车是一个交通工具
    • 继承的合理性:引用《大话西游》里的一句话来描述继承的。“人是人他妈生的,妖是妖他妈生的!”

3.OC中如何实现继承

  • 在声明子类的时候,在子类名称后面通过:父类名称方式来实现继承
@interface 子类名称 : 父类名称......@end

问题1:什么是继承?什么是父类?什么是子类?如何实现继承?

  • 子类获得父类的特性就是继承
  • 被继承的这个类我们称之为父类/ 超类
  • 继承了某个类的类我们称之为子类
  • 在声明子类的时候,在子类名称后面通过:父类名称方式来实现继承

    @interface 子类名称 : 父类名称//其他语句@end
  • 当B类继承A类, 那么B类就拥有A类所有的属性和方法(类方法/对象方法)


继承的相关特性


本小节知识点:

  1. 方法重写
  2. 继承中方法调用的顺序
  3. 继承的注意事项

1.方法重写

  • 在子类中实现与父类中同名的方法,称之为方法重写;
  • 重写以后当给子类发送这个消息的时候,执行的是在子类中重写的那个方法,而不是父类中的方法。
  • 如果想在子类中调用被子类重写的父类的方法,可以通过super关键字

  • 注意:在继承中方法可以重写, 但是属性(成员变量)不能重写

2.继承中方法调用的顺序

  • 在自己类中找
  • 如果没有,去父类中找(逐级往上找)
  • 如果父类也没有,就还往上找,直到找到基类(NSObject)
  • 如果NSObject都没有就报错了:
reason:-[Iphone signalWithNumber:]: unrecognized selector sent to instance 0x1003043c0
  • 总之:如果找到了就执行这个方法,并且不再往后查找了,如果一直都到NSObject都没找不到则报错。

3.继承的注意事项

  • 子类不能定义和父类同名的成员变量,私有成员变量也不可以;因为子类继承父类,子类将会拥有父类的所有成员变量,若在子类中定义父类同名成员变量 属于重复定义。

  • OC类支持单一继承,不支持多继承;也就是说一个类只能有一个直接父类

  • OC类支持多层继承


问题1:方法重写的使用场景?

使用场景:当从父类继承的某个方法不适合子类,可以在子类中重写父类的这个方法。

问题3:继承的条件是什么?

不要以为继承可以提高代码的复用性, 以后但凡发现多个类当中有重复代码就抽取一个父类 只要满足一定的条件我们才能使用继承;

条件: XXXX 是 XXX / 某某某 is a 某某某

问题4:继承的优点是什么?

  • 提高代码的复用性

  • 可以让类与类之间产生关系, 正是因为继承让类与类之间产生了关系所以才有了多态

问题5:继承的缺点是什么?

耦合性太强(依赖性太强)


Super关键字


本小节知识点:

  1. super基本概念
  2. super的作用

1.super基本概念

  • super是个编译器的指令符号,只是告诉编译器在执行的时候,去调谁的方法.

    1. self是一个隐私参数;2. super 并不是隐藏的参数,它只是一个“编译器指示符”,它和 self 指向的是相同的消息接收者

2.super的作用

  • 使用super一定会直接调用父类中的某个方法
  • super在对象方法中,那么就会调用父类的对象方法
  • super在类方法中,那么就会调用父类的类方法

问题:super使用场景?

答: 子类重写父类的方法时想保留父类的一些行为


多态基本概念


本小节知识点:

  1. 【了解】什么是多态?
  2. 【掌握】多态的条件
  3. 【了解】多态的优点

1.什么是多态?

  • 什么是多态:多态就是某一类事物的多种形态

    猫: 猫-->动物狗: 狗-->动物男人 : 男人 -->人 -->高级动物女人 : 女人 -->人 -->高级动物
  • 程序中的多态:父类指针指向子类对象


2.多态的条件

  • 有继承关系
  • 子类重写父类方法
  • 父类指针指向子类对象

    狗 *g = [狗 new];动物 *a = [狗 new];猫 *c = [猫 new];动物 *a = [猫 new];
  • 表现:当父类指针指向不同的对象的时候,通过父类指针调用被重写的方法的时候,会执行该指针所指向的那个对象的方法


3.多态的优点

  • 多态的主要好处就是简化了编程接口。它允许在类和类之间重用一些习惯性的命名,而不用为每一个新的方法命名一个新名字。这样编程接口就是一些抽象的行为的集合,从而和实现接口的类的区分开来。

  • 多态也使得代码可以分散在不同的对象中而不用试图在一个方法中考虑到所有可能的对象。这样使得您的代码扩展性和复用性更好一些。当一个新的情景出现时,您无须对现有的代码进行 改动,而只需要增加一个新的类和新的同名方法。

  • 优点总结:提高了代码的扩展性,复用性


多态的注意点

  • 如果父类指针指向子类对象, 需要调用子类特有的方法, 必须先强制类型转换为子类才能调用

多态的实现


本小节知识点:

  1. 【掌握】如何实现多态
  2. 【了解】多态的原理
  3. 【掌握】多态的注意点

1.如何实现多态

  • Animal是父类,子类有Cat 和 Dog,子类分别重写了父类中的eat方法;实例化对象的时候可以用下面的方法:
Animal *animal = nil;//实例化猫的对象animal = [Cat new];[animal eat];//实例化狗的对象animal = [Dog new];[animal eat];

2.多态的原理

  • 动态绑定:

    • 动态类型能使程序直到执行时才确定对象的真实类型
    • 动态类型绑定能使程序直到执行时才确定要对那个对象调用的方法
  • OC不同于传统程序设计语言,它可以在运行时加入新的数据类型和新的程序模块:动态类型识别,动态绑定,动态加载

  • id类型:通用对象指针类型,弱类型,编译时不进行具体类型检查

3.多态的注意点

  • 1)如果存在多态,父类是可以访问子类特有的方法

    假设 子类 Dog 有一个特有的方法bark[dog bark];Animal *an2 = [Dog new];[(Dog*)an2 bark]; //把父类的指针,强制类型转换
  • 2)如果不存在多态,父类是不可以访问子类特有的方法的

    Animal *an3 = [Animal new];[(Dog*)an3 bark]; //错误的,不能强制转换

实例变量修饰符


本小节知识点:

  1. 【理解】实例变量的作用域
  2. 【掌握】变量修饰符在子类中的访问
  3. 【了解】实例变量作用域使用注意事项

1.实例变量的作用域

  • 1)@public (公开的)在有对象的前��下,任何地方都可以直接访问。
  • 2)@protected (受保护的)只能在当前类和子类的对象方法中访问
  • 3)@private (私有的)只能在当前类的对象方法中才能直接访问
  • 4)@package (框架级别的)作用域介于私有和公开之间,只要处于同一个框架中相当于@public,在框架外部相当于@private

2.变量修饰符在子类中的访问

  • 1)@private私有成员是能被继承,也不能被外部方法访问。
  • 2)@public 公有成员能被继承,也能被外部方法访问。
  • 3)@protected 保护成员能够被继承,不能够被外部方法访问。

3.实例变量作用域使用注意事项

  • (1)在@interface @end之间声明的成员变量如果不做特别的说明,那么其默认是protected 的。
  • (2)一个类继承了另一个类,那么就拥有了父类的所有成员变量和方法,注意所有的成员变量它都拥有,只是有的它不能直接访问。例如@private的

问题1:实例变量修饰符有那几个关键字?被修饰的实例变量在本类/子类/其他类中是否能被访问?

  • @public

    1. 可以在其它类中访问被public修饰的成员变量2. 也可以在本类中访问被public修饰的成员变量3. 可以在子类中访问父类中被public修饰的成员变量
  • @private

    1. 不可以在其它类中访问被private修饰的成员变量2. 可以在本类中访问被private修饰的成员变量3. 不可以在子类中访问父类中被private修饰的成员变量
  • @protected

    1. 不可以在其它类中访问被protected修饰的成员变量2. 可以在本类中访问被protected修饰的成员变量3. 可以在子类中访问父类中被protected修饰的成员变量    注意: 默认情况下所有的实例变量都是protected
  • @package

    1. 介于public和private之间的2. 如果是在其它包中访问那么就是private的3. 如果是在当前代码所在的包种访问就是public的

问题2:如何判断实例变量修饰符作用域?

  • 从出现的位置开始, 一直到下一个修饰符出现,如果没有遇到下一个实例变量修饰符, 那么就会修饰后面所有的实例变量

description方法


本小节知识点:

  1. 【掌握】description基本概念
  2. 【掌握】description重写的方法
  3. 【了解】description陷阱

1.description基本概念

  • NSLog(@”%@”, objectA);这会自动调用objectA的description方法来输出ObjectA的描述信息.

  • description方法默认返回对象的描述信息(默认实现是返回类名和对象的内存地址)

  • description方法是基类NSObject 所带的方法,因为其默认实现是返回类名和对象的内存地址, 这样的话,使用NSLog输出OC对象,意义就不是很大,因为我们并不关心对象的内存地址,比较关心的是对象内部的一些成变量的值。因此,会经常重写description方法,覆盖description方法 的默认实现


2.description重写的方法

  • 对象方法

    /*对象方法:当使用NSLog输出该类的实例对象的时候调用*/-(NSString *) description{  return [NSString stringWithFormat:@"狗腿数:%d,狗眼数%d\n",_legNum,_eyeNum];}
  • 类方法

    /**类方法:当使用NSLog输出该类的类对象的时候调用*/+(NSString *) description{  return @"+开头的description方法";}

3.description陷阱

  • 千万不要在description方法中同时使用%@和self,下面的写法是错误的

    - (NSString *)description {  return [NSString stringWithFormat:@"%@", self];  //这样会造成死循环,每次执行到%@的时候,由于是self都会调用description方法,不断的返回去调用自己}
  • 同时使用了%@和self,代表要调用self的description方法,因此最终会导致程序陷入死循环,循环调用description方法

  • 当[NSString stringWithFormat:@“%@”, self]; 使用它时,循环调用,导致系统会发生运行时错误。

  • 当该方法使用NSLog(“%@”,self) 时候, 系统做了相关的优化,循坏调用3次后就会自动退出


问题1:使用%@打印一个对象,输出的是什么内容?%@的原理是什么?

  • %@是用来打印对象的, description方法默认返回对象的描述信息(默认实现是返回类名和对象的内存地址). 其实%@的本质是用于打印字符串.

  • 只要利用%@打印某个对象, 系统内部默认就会调用父类的description方法 调用该方法, 该方法会返回一个字符串, 字符串的默认格式 <类的名称: 对象的地址>

问题2:重写description方法注意点?

  • 如果在description方法中利用%@输出self会造成死循环

  • 建议: 在description方法中尽量不要使用self来获取成员变量 因为如果你经常在description方法中使用self, 可能已不小心就写成了 %@, self


总结


0 0