一.setter(赋值)方法:
1.使用背景:
我们在为对象属性赋值的时候,如果我们希望这个数据可以做一个逻辑验证.当属性的值在这个逻辑范围之内我们就把这个值赋值给属性,否则我们就做默认处理.这个时候类提供了一个方法,这个方法专门为这个属性赋值,这个方法叫做setter方法.
2.注意事项:
这个方法一定是1个对象方法,因为这个要为属性赋值;
这个方法没有返回值,因为这个方法做的事情仅仅是为属性赋值就可以了;
这个方法的名称必须是以set开头,跟上去掉下划线首字母大写的属性名;
这个方法一定是有参数的,参数的类型一定是属性的类型.参数的名称和属性的名称一致(要去掉下划线)
在方法的实现中,判断传入的数据是否符合逻辑.如果符合逻辑就赋值,否则做默认处理.
二.getter(取值)方法
1.使用背景:
我们通过setter方法可以为属性增加一个逻辑判断,但是在没有@public的情况下,外界是无法取出属性的值的(此处不包括声明成全局变量).那么这个时候系统就提供给我们一个get方法.
2.注意事项:
这个方法一定是1个对象方法,因为这个方法做的事情就是要拿到属性的返回值;
这个方法肯定有返回值,返回值的类型和属性的类型一致;
这个方法的名称直接就是属性的名称(去掉下划线的);
这个方法没有参数;
这个方法的实现是直接将属性的值返回;
这个时候,如果外界希望得到属性的值,那么就只需要调用这个getter方法就可以了.
三.继承:
1.继承是类在继承,而不是对象在继承;也就是说子类从父类继承,子类中就拥有父类中定义的所有成员变量,这只是类继承,而我们在创建对象的时候,子类的对象和父类的对象是毫无关系的.
2.注意事项:
如果有一个成员变量不是所有的子类都拥有的,那么这个成员就不应该定义在父类之中.因为一旦定义在父类之中,那么所有的子类全部都有了.
3.特性:
3.1.单根性:1个类只能有一个父类,不能有多个父类;
3.2.传递性:A类从B类继承,B类从C类继承,那么A类就同时拥有B,C类的成员.
四.对象方法跟类方法之间的关系:
1.对象方法:
1.1. 使用减号开头
1.2.调用的时候可以直接访问对象的属性
1.3.调用的时候必须使用对象调用
2.类方法:
2.1.以加号开头
2.2.调用的时候不可以直接访问对象的属性
2.3.调用的时候必须使用类调用
3.区别:
对象方法可以直接调用其他的对象方法,也可以直接调用其他的类方法(减号方法中可以直接调用对象,也可以直接调用其他类的减号方法)
类方法中不可以直接调用对象方法,但可以调用类方法(加号方法中不可以直接调用对象,但是可以调用其他的加号方法)
备注:要想在减号方法中调用加号方法,就必须使用当前类创建一个对象,然后使用对象来调取对应的属性和减号方法.
五.static关键字
1.OC中的static关键是
static不能修饰属性,也不能修饰方法;
static可以修饰方法中的局部变量.
如果方法中的局部变量被static修饰,那么这个变量就会变成静态变量,存储在常量区.当方法执行完毕以后不会回收,下次再执行这个方法的时候直接使用而不会在声明了.(相当于存储在本地一样,只有当当前视图控制器消失的时候,该属性才会变成原始的属性值)
六.super关键字
1.使用背景
a.可以使用在类方法和对象方法之中;
b.在对象方法中可以使用super关键字调用当前对象从父类继承过来的对象方法;
c.在类方法中可以使用super关键字调用当前从父类继承过来的类方法;
e.super只能用来调用父类的对象方法或者类方法,不能用来访问属性;
f.super特指这个方法是从父类继承过来的.
七:访问修饰符
1.访问修饰符是用来修饰布局变量的,可以限定对象的属性在那段范围之中访问,
a.@private:私有 修饰的属性只能在本类内部访问,只能在本类的方法实现中访问;
b.@protected:受保护的 修饰的属性只能在本类和本类的子类中访问(如果不为属性指定访问的修饰符,那么默认的就是@protected);
c.@package: 修饰的属性可以在当前框架中访问;
d.@public:公共的 修饰的属性可以在任何地方进行访问.
2.使用建议:
a.@public:无论什么情况下都不会使用,因为属性不要直接暴露给外界;
b.@private:如果属性只想在本类中使用,不想在子类中使用,那么就使用它(虽然这个属性是私有的,但是在外界的时候,Xcode仍然会提示这个对象中有这个属性,只不过是没有权限访问.这个时候我们可以将属性写在@implementation的大括号之中.他们两者之间唯一的区别就是:属性定义在@interface之中并标记为@private的时候,Xcode还进行提示而写在@implementation的时候Xcode是不会进行提示的);
c.@protected:如果你希望属性只在本类和本类的子类中使用;
e.推荐使用默认的@protected.
3.访问修饰符只能用来修饰属性,不能用来修饰方法.
八.里氏替换原则(简称:LSP)
1.定义:子类可以替换父类的位置,并且程序的功能不受影响.
2.里氏替换原则的表现形式:当1个父类指针指向1个子类对象的时候,这里就有里氏替换原则
3.作用
a.一个指针当中不仅可以存储本类对象的地址还可以存储子类对象的地址;
b.如果一个指针的类型是NS0bject类型的,那么这个指针中可以存储任意的OC对象的地址;
c.如果一个数组的元素的类型是1个OC指针类型的,那么这个数组中不仅可以存储本类对象还可以存储子类对象.
实例:
Person*ps[3];
ps[0]=[Person new];
ps[1]=[Student new];
d.如果一个数组的元素是NS0bject指针类型的,那么意味着任意的OC对象都可以存储在这个数组之中;
e.如果一个方法的参数是一个对象,那么我们在为这个参数传值的时候,可以传递一个本类对象 也可以传递一个子类对象.对方法中的代码不会有丝毫的影响.
九.方法的重写
1.使用背景:
当我们在继承的时候,虽然拥有了父类的行为,但是行为具体的实现和父类的实现不一样.那么子类就自己按照自己的方式重写这个方法就可以了.
2.如何重写:
直接在类的实现 中将这个方法重新实现一遍就可以了.
3.什么时候子类需要重写父类的方法:
子类拥有父类的行为,但是子类这个行为的实现和父类不一样.那么就按照自己的方法重写这个方法就可以了.
4.当一个父类的指针指向一个子类对象的时候,通过这个父类指针调用的方法,如果这个方法在子类对象中重写了,则调用的就是子类重写的方法.
十:多态
1.定义:
指的是同一个行为,对于不同的事物具有完全不同的表现形式.
十一:结构体与类的区别
1.结构体与类的区别:
结构体的格式:
typedef struct
{
intday;
intmonth;
}Date;
typedef struct CG_BOXABLE CGRect CGRect;
2.结构体与类的不同点:
a.结构体只能封装数据,而类不仅可以封装数据还可以封装方法;
b.结构体变量分配在栈空间(如果是1个局部变量的情况下),而对象分配在堆空间;
栈的特点:空间相对较小,但是存储在栈中的数据访问的效率更高一些;
堆的特点:空间相对较大,但是存储在堆中的数据访问的效率相对较低一些;
十二.SEL(选择器)
1.SEL 全称叫做selector选择器;
2.SEL其实是1个类,SEL对象是用来存储1个方法的;
3.如何将方法存储在类对象之中:
a.先创建1个SEL对象;
b.将方法的信息存储在这个SEL对象之中;
c.再将这个SEL对象作为对象的属性;
4.如何拿到存储方法的SEL对象
a.因为SEL是1个typedef类型的,在自定义的时候已经加*了,所以我们在声明SEL指针的时候不需要加*;
b.去存储方法的SEL对象,SEL s1=@selector(方法名);
5.方法调用的本质
实例:
[p1 sayHi];
内部实现原理:
a.先拿到存储sayHi方法的SEL对象,也就是拿到存储sayHi方法的SEL数据,SEL消息;
b.将这个SEL消息发送给p1对象;
c.这个时候,p1对象接收到这个SEL消息以后就知道要调用这个方法;
d.根据对象的isa指针找到存储类的类对象;
e.找到这个类对象以后,在这个类对象中去搜索是否有和传入的SEL数据相匹配的,如果有就执行,如果没有再找父类直到NS0bject
总结:OC最重要的一个机制就是消息机制,而调用方法的本质就是为对象发送SEL消息的.切方法是以SEL对象的形式存储起来的.
实例:
GetPhotoViewController *vc = [[GetPhotoViewController alloc]init];
//调用GetPhotoViewController里面的一个方法
SEL s1=@selector(ziDingYiFangFa);
//为VC对象发送一条s1消息.
[vc performSelector:s1];
十三.property的作用
1.自动生成一个私有属性,属性的类型和@property类型一致,属性的名称和@property名称一致,属性的名称自动的加一个下划线;
2.自动生成这个属性的getter setter方法的声明
3.自动生成这个属性的getter setter方法的实现.
十四.instancetype关键字
1.如果方法的返回值是instancetype,那么就代表方法的返回值是当前这个类的对象;
2.使用建议:
a.如果方法内部是在创建当前类的对象,不要写死成类名[类名 new],而是使用self代替类名;
b.如果方法的返回值是当前类的对象,也不要写死.而是写instancetype
3.id和instancetype的区别:
a.instancetype只能作为方法的返回值,不能在别的地方使用;id既可以声明指针变量也可以作为参数,也可以作为返回值.
b.instancetype是1个有类型的,代表当前类的对象,id是1个无类型的指针,仅仅是1个地址.
十五.动态类型检测
1.我们在调用对象中方法的时候一般都是先写代码来判断一下,对象中是否有这个方法,如果有在执行下去,如果没有就不在去执行
2.判断对象中是否有这个方法可以执行;
+ (BOOL)respondsToSelector:(SEL)aSelector;
3.判断指定的对象是否为指定类的对象或者子类对象;
- (BOOL)isKindOfClass:(Class)aClass;
4.判断对象是否为指定类的对象,不包括子类;
- (BOOL)isMemberOfClass:(Class)aClass;
5.判断类是否为另外一个类的子类
+ (BOOL)isSubclassOfClass:(Class)aClass;
十六.重写init方法和自定义构造方法
如果我们想让创建的对象的属性默认是不是nill NULL 0,而是我们自定义的,那么这个时候,我们就可以重写init方法,在这个方法中按照我们自己的想法为对象的属性赋值.
1.重写init方法的规则
a.必须要先调用父类的init方法,然后将方法的返回值赋值给self;
b.调用init方法初始化对象有可能会失效;如果初始化失败,返回的就是nil,
c.判断初始化是否成功.判断self的值是否为nil,如果不为nil,说明初始化成功;
d.如果初始化成功,就初始化当前对象的属性;
e.最后返回self的值.
2.为什么要调用父类的init方法?
因为父类的init方法会初始化父类的属性,所以要保证当前对象中的父类属性也同时被初始化;
3.为什么要赋值给self?
因为调用父类的init方法,会返回初始化成功的对象.实际上返回的就是当前对象,但是我们要判断是否初始化成功.
4.自定义构造方法:
a.自定义构造方法的返回值必须是instancetype;
b.自定义构造方法的名称必须以initwith开头;
c.方法的实现和init的要求一样;
十七.内存管理概述
1.内存中的五大区域
栈:局部变量---当局部变量的作用局被执行完毕之后,这个局部变量就会被系统立即回收===>系统自动处理;
堆:OC对象,使用C函数申请的空间-----系统不会自动回收,当程序结束的时候就会被系统回收
BSS段:未初始化的全局变量,静态变量-----一旦初始化就回收并转存到数据段之中===>系统自动处理;
数据段:已经初始化的全局变量和静态变量------直到程序结束的时候,才会被回收===>系统自动处理;
代码段:代码-----程序结束的时候,系统会自动回收存储在代码段中的数据===>系统自动处理;
十八.类别使用的注意事项
使用类别的注意事项:
1.类别中只能增加方法,不能增加属性;
2.在类别中可以写@property,但是不会自动生成私有属性,也不会自动生成getter setter的实现,只会生成getter setter的声明.所以你需要自己写getter setter的实现.也需要自己定义属性,这个属性就必须在本类当中,不能在类别当中;
3.在类别方法实现中不可以直接访问本类的真私有属性(定义在本类的@implementation),但是可以调用本类的getter setter来访问属性;
本类的@property生成的私有属性,只可以在本类的实现中进行使用,分类中不能直接访问私有属性(也就是直接使用下划线进行调用本类中声明的属性),但是分类中可以使用getter sette方法来访问(也就是可以使用self.属性来进行调用)
4.当类别中有和本类中同名的方法的时候,优先调用分类的方法,哪怕没有引入分类的头文件.如果多个分类中有相同的方法,优先调用最后编译的分类.
十九.扩展(Extension)
1.扩展(Extension)的定义:
1.1.是一个特殊的分类,所以扩展(Extension)也是类的一部分;
1.2.扩展这个特殊的分类没有名字;
1.3.是有声明没有实现,需要和本类共享一个实现,也就是只有.h文件,在扩展里面声明的方法需要在本类的.m文件里面进行实现;
2.扩展的语法:
@interface 本类名()
@end
没有实现,和本类共享一个实现.
注意:在创建扩展的时候,对谁进行扩展则class的地方就应该选哪个类作为父类
3.扩展的基本使用
3.1.扩展的本质是一个分类,作为本类的一部分,只不过是一个特殊的分类,没有名字;
3.2.扩展只有声明,没有单独的实现文件,和本类共用一个实现文件,也就是共用一个.m文件;
4.扩展和类别的区别:
4.1.类别有名字,扩展没有名字;
4.2.类别都拥有自己的实现文件和声明文件(拥有自己的.h文件和.m文件);扩展只有声明文件没有实现文件,需要和本类共用实现文件(也就是只有.h文件,没有.m文件);
4.3.类别中只能新增加方法,不能新增属性,而扩展不仅可以新增方法也可以新增属性;
5.扩展使用场景:
5.1.要为类写一个私有的@property.
生成getter,setter方法只能在类的内部访问,不能在外部访问.
5.2.扩展100%不会生成一个单独的文件,而是直接写在本类的实现文件中,实例:
@interface ViewController ()
@end
这个时候,写在扩展中的成员,就相当于这个类的私有成员,只能在本类的实现中访问.外部不能访问.
二十.block块的使用
1.typedef的作用是将block进行简写;
2.格式:typedef 返回值类型(^新类型)(参数类型)
3.typedef void(^NewType)();====>代表重新定义了一个类型叫做NewType,是一个block类型.无参无返回值的block类型.
4.关于block块访问外部变量的知识点:
4.1.在block代码块的内部可以取定义在外部的变量的值,指定义在外部的局部变量和全局变量;
4.2.在block代码块的内部可以修改全局变量的值,但是不能修改定义在外部的局部变量的值;
4.3.如果我们希望我们定义的局部变量可以允许在block代码的内部去修改外部的局部变量,那么我们就为这个局部变量添加一个__block的修饰符.
二十一.协议:protocol
1.协议:protocol是专门用来声明一大堆方法的.(不能声明属性,也不能实现方法,只能用来写方法的声明).只要某各类遵循了这个协议,就相当于拥有这个协议的所有的方法的声明.
2.协议的声明:
@protocol 协议名称<NSObject>
方法的声明
@end
在协议中,只能用来声明方法,协议的作用就是专门用来写方法声明的.
3.类遵循协议
如果想要让一个类,拥有协议中定义的所有的方法声明,那么就让这个类遵循这个协议;
类只要遵循一个协议,那么这个类就拥有了这些协议中定义的所有的方法的声明了.
4.遵守协议的写法:
直接在需要使用协议的类的父类后面增加尖括号<协议的名称>
5.协议中的关键字
5.1.@required:
在协议中,如果方法的声明被@required修饰,那么遵循协议的这个类必须要实现这个方法,否则编译器就会发出警告;
5.2.@optional:
在协议中,如果方法的声明被@optional修饰,那么遵循协议的这个类如果不实现这个方法,编译器也不会报警告;
其实,无论是@required还是@optional你都可以不实现,编译器是不会报错的,仍然可以编译运行.唯一的区别就是:当遵循协议的类不实现协议中的方法的时候,@required会给一个警告,@optional连警告都没有.
这两个关键字的主要作用:在于程序员的沟通,告诉遵循协议的类,那些方法是必须实现的,那因为这些方法我会调用.默认是@required
6.协议之间可以相互继承
6.1.继承的语法:
@protocol 协议名称 <父协议名称>
@end
7.在Foundtion框架中,有一个类,叫做NS0bject是所有OC类的基类;在Foundtion框架中,有一个协议,叫做NS0bject.NS0bject协议被NS0bject类遵守,所以,NS0bject协议中的所有的方法,全部的OC类都拥有了.也就是说,所有的OC类都遵循了NS0bject协议,NS0bject协议就是一个基协议.
二十二:OC中的框架含义
1.框架:就是系统(苹果)或者第三方(其他的一些高手)事先写好了一些比较牛X功能的类,把这些类交给我们使用,这些类的集合我们叫做框架.
2.Foundation框架:是一个包,这里面有很多类,函数,定义了一些数据类型.这个框架中的类都是一些最基础的类.
网友评论