OC全称Objective-C(面向对象的C),是以C语言为基础的,并结合Smalltalk特征扩展出来的一种面向对象编程的语言。
OC语言有一下几个特点:
1.OC是以C语言为基础的,并在C语言的基础上增加了一层最小的面向对象的语法;
2.OC可以完全兼容C语言;
3.OC可以开发macOS平台、iOS平台、watchOS平台及tvOS平台的应用程序(但是现在Swift也在慢慢兴起)。
OC中有很多特有的关键字,而且这些关键字基本上都是以@开头,比如:
@interface、@implementation、@end
@public、@protected、@private、@selector
@try、@catch、@throw、@finally
@protocol、@optional、@required、@class
@property、@synthesize、@dynamic
还有一些OC比较特征性的关键字,比如:self、super、id、_cmd、__block、__strong、__weak等
这些基本都是C语言没有的,而且有些语法OC与C也存在着差异,例如@"Hello"是OC中的字符串写法,而"Hello"或‘Hello’则是C语言中字符串写法,在C中没有@来修饰字符串,同样正因为OC是以C为基础的所以C中的基本数据类型(char、int、float、double、bool等)也是可以在OC中使用的。
而OC与C语言面向的事物并不一样,OC是面向对象的,C是面向过程的,面向对象和面向过程只是解决问题的两种不同的思想,本质上都是为了解决问题,就好比建房子,对于C语言来说,关注的是打地基-砌墙-搭屋顶-粉刷-装门窗-完工的这一个完整的过程,但对于OC来说,它要关注的就是把每个环节细分到具体对象,把打地基、砌墙、搭屋顶的工作细分给泥瓦匠,粉刷的工作分给粉刷匠,装门窗的工作分给木匠,生活中也是这样,打电话你会想到手机、吃饭你会想到服务员、汽车坏了你会想到汽修师傅,所以在OC的世界里,万物皆可为对象。
类
面向对象解决问题的核心就是对象,那么解决问题就要创建对象,在OC里面创建对象,就必须理解类的概念。在我们的生活逻辑中,提到类就会想到人类、蔬菜、水果等等,人类分你、我、她,茄子、辣椒、白菜都是蔬菜,苹果、梨子、香蕉属于水果,那么什么是对象,对象就是人类中的某个你我他,蔬菜中的某个茄辣白,水果中的某个苹梨香,换句话说,类就是人们主观意识存在用来描述一类事物的,对象就是类的具体存在,OC利用类来创建对象,要想创建对象,就必须先有类。因此,面向对象解决问题应该先考虑需要设计哪些类,再利用类创建多少个对象。
类的设计需要关注3个要素:类名、属性、行为。
类名:顾名思义即事物(类)的名称,类名的设计有一定的规范,不可随意设计,对于开发者来说以下的最基本的规范还是要遵守的:1.第一个字母必须大写(虽然可以小写);2.不能带有下划线;3.如果存在多个英文,请用驼峰标识
属性:用来描述类特征的一些指标参数,如人有身高、年龄、姓名等属性信息
行为:类所具有的一些技能(功能),比如人有跑、走、笑等行为能力
类由类声明(@interface)和类实现(@implementation)两部分构成,@interface将类的属性及行为暴露出来供给外部使用,@implementation则隐藏在身后将各种行为(功能)构造实现。
属性
说到属性,必须搬出成员变量,成员变量是在类中声明的变量,类实例化变成对象后,成员变量也就成了实例变量,成员变量以下划线开头,成员变量的价值就是存储对象的数据,也就是说对象的数据实际上是存在实例变量(成员变量)里的,而属性则是自动帮我们声明了成员变量。
属性也帮我们自动声明并实现了setter和getter方法,setter方法实际上就是用来给成员变量(实例变量)赋值的,getter方法则实际上是用来获取成员变量(实例变量)的值的,而“.”点语法访问属性,实际上是调用了setter和getter方法。
在外部函数中,不能直接访问对象的成员变量,因为编译器不开放相关权限,但点语法可以访问成员变量,实际上是调用了setter和getter方法,p1.weight调用getter方法,p1.weight = 80调用setter方法。
所以属性的本质还是在调用方法,编译器帮我们自动实现一些setter方法、getter方法和声明相应的成员变量。
成员变量的作用域
成员变量的作用域分为四种:
1.@private:私有的,只能在当前类的对象方法中直接访问(@implementation中声明的成员变量默认是@private)
2.@protected:受保护的,能在当前类及子类方法中访问,其他类不能访问(@interface中声明的成员变量默认是@protected)
3.@public:公开的,在任何地方都能直接访问对象的成员变量
4.@package:在同一个框架,介于@private和@public之间
在类声明(@interface)和类实现(@implementation)中不能声明同名的成员变量
方法
OC中的method我们称作方法,C中的“方法”叫函数,在OC中创建类的实例对象的方法叫构造方法,给对象调用的方法叫对象方法也叫实例方法,而有一种方法不需要实例化出对象由类直接调用的方法叫类方法,也有些人称这种方法(类方法)叫工厂方法。
公有和私有方法
在.h文件中声明的方法为公有方法;
在.m文件中声明的方法为私有方法。
构造方法主要是用来进行对象的初始化,在OC中凡是以init开头的方法都是构造方法,一个对象必须在初始化后才可以使用,否则对象中的数据有可能不合法。OC语言的初始化需要开发者主动调用方法完成,而且需要在创建对象的时候同时就要初始化。
对象方法是以“-”号开头的方法,也称实例方法和成员方法,是通过对象指针来调用的,所以前提就是必须有对象,在对象方法中可以访问当前对象的成员变量。
类方法是以“+”号开头的方法,是属于类的,通过类名调用,和对象无关,不需要实例出对象,执行效率高;在类方法中不能访问成员变量,所以当方法内部不需要使用到成员变量、属性的时候,就可以改为类方法,同样类方法也可以创建对象或简洁地创建对象,比如创建单例对象;我们还可以通过类方法,对外公开一些简单易用的接口。
在上述方法中,self是最常用的引用对象,在构造方法和对象方法中self指向当前对象的指针,当向一个对象发送消息的时候,对象会调用相应的方法,调用的同时,会将此对象的地址传递给方法中的self指针,那么在方法中就可以通过self指针来访问当前对象的属性,同样在类的方法中包括类方法,方法和方法之间使用self相互调用。
面向对象的语言有三大特性:继承性、封装性、多态性。
继承
继承其实是一种代码复用的技术,是类与类之间的一种关系,父类和子类形成了继承的父子关系。父类拥有的属性、成员变量和方法,子类直接获得,这个过程叫继承,比如B类继承了A类,那么A类中的所有的属性、成员变量和方法B类都可以拥有,那么B类就叫做A类的子类,A类就叫做B类的父类。继承也可以称为“派生”,子类在父类的基础上,衍生出自己独有的属性和方法,这个过程叫做派生,继承和派生是描述同一事物的两种侧重。
子类以单继承的方式继承父类,一个类有且只有一个父类,OC的类必须直接或间接地继承NSObject类。子类在继承父类后,子类可以根据实际需求重写父类的方法,当子类对象调用重写的方法时不会再执行父类的方法只会执行子类的方法,子类在初始化时要调用父类的初始化方法,子类在声明新的成员变量时不能与父类的成员变量重名。
继承有优点也有缺点:
U点:1.能够抽取重复代码,减少重复代码量;2.能够建立类之间的关系,使思路更清晰;3.子类可以拥有父类中所有的成员变量和方法;4.能够使用多态,满足实际开发需求。
Q点:1.在某些情况下会增加程序的复杂度,当系统很复杂时,维护性和拓展性就会降低;2.耦合性太强,继承不能乱用。
所以在什么时候使用继承才能达到事半功倍的效果呢?
当工程中需要创建大量相似的类的时候,比如象棋,象棋由很多棋子组成,而棋子都有相似的特点,那么就可以创建一个棋子类作为父类,然后由父类继承出“卒/兵”、“车马象”、“士”、“将/帅”、“炮”这些子类,完成不同的任务。又例如继承一个官方类,添加新的属性和方法,创建一个更符合当前工程项目的新类,来满足实际的开发需求。
多态
所谓多态,就是指同一个接口(方法)不同的实现,从OC中的消息机制来看,就是给不同的对象发送相同的消息但是反应却不同,其实在上述继承的内容中子类重写父类的方法也可以叫做多态,在继承中对于某个类型的指针,它可以指向它的任何子类对象,也可以指向本类类型的对象,对于指针指向不同子类的对象,向此对象发送相同的消息,就会执行不同的动作,比如在加油站,加油员会问不同司机同样的问题“请问加什么油?”,不同司机有回答“92#”、“95#”、“柴油”的,遇到大货车司机还可能会回答“加水”。