Object-C基础——类与对象
Posted 一步一步往上爬的小蜗牛
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Object-C基础——类与对象相关的知识,希望对你有一定的参考价值。
Object-C的面向对象
类:一批具有相同特征的对象的统称(一批相似对象的概念)
类:一批对象的总称。
对象:具体存在的东西。
定义类的语法:
Object-C定义类,需要2个部分:
头文件部分(声明部分) —— 相当表盘部分,暴露出来供用户操作的。
@interface <类名> :NSObject
{
成员变量
}
方法声明
@end
类名:只要是一个标识符即可。但从程序可读性的角度来看,类名必须是由一个或多个有意义的单词连缀而言。
成员变量:用于描述该类或该类的对象所具有的状态信息。程序只记录与业务相关的状态信息。
语法:<类型> <变量名>;
方法:用于描述该类或该类的对象所具有的行为。程序只记录与业务相关的行为。
方法语法:
+|- (返回值类型) 方法名: (形参类型1) 形参名1 形参标签2: (形参类型2) 形参名2 形参标签3: (形参类型3) 形参名3 ...
+表明该方法属于类本身,该方法只能由类来调用;-表明该方法属于该类的对象,因此只能由于对象调用。
返回值类型,可以是任意有效的类型。
方法名,只要是一个有效的标示符即可。但从程序可读性角度来看,方法名应该是一个或多个单词连缀而言,最好方法名是动词。
形参列表:除了第一个形参之外,后面每个形参都需要3个部分:形参标签: (形参类型) 形参名
实现部分 —— 相当于表体部分,被彻底隐藏的,但负责提供表盘部分的显示。
@implementation <类名>
{
成员变量 —— 此处定义的成员变量,相当于被隐藏的成员变量。
}
实现接口部分定义的所有方法。
额外定义实现部分的方法。—— 此处额外定义的方法,相当于是被隐藏的方法,因此不能被调用。
@end
类的作用:
1. 定义变量。所有类,都属于指针类型。
2. 创建对象。
3. 调用类方法。
4. 用于被继承、派生子类。
【不存在的】: 可以访问类变量 ———— 但不存在。Object-C的类不能定义类变量。
创建对象
[[类名 alloc] init]
init,包括后面的系列initWithXxx方法,被称为初始化方法。
[类名 new] - 很少使用。
对象的作用:
1. 调用实例方法
2. 访问实例变量
对象变量 -> 成员变量
调用方法
[类|对象 方法:参数1 形参标签2: 参数2 形参标签3: 参数3...];
对象与指针
用自定义类来声明变量时,都需要在类名后添加一个*,表明这是一个指针。
指针:意味着,当程序把一个对象赋值给指针变量时,实际上只是把该对象的首地址存入指针变量,并未真正把对象存入指针中。
同一个对象,可以被很多个指针变量(引用变量)指向(引用)它。
反过来:供一个指针变量,最多只能指向一个对象。
对象 —— 只是赋值,不会创建对象。要看到allocate(分配内存)才会创建对象。
dealloc —— 删除内存,销毁该对象。
self 关键字 代表了调用方法的调用者。通俗来说,谁调用方法,self就代表谁。
如果在实例方法中,总是由实例调用,因此self总是代表调用该方法的对象;
如果在类方法中,总是由类调用,因此self总是代表调用该方法的类本身。
self,主要是作为一个代词。 当它出现在任何方法中,谁调用该方法,self就代表了谁。
id类型
C/Object-C都是强类型的语言,指定的类型的变量,只能接受指定类型的对象。
但id不同,它可以接受任意类型的对象。
对于id类型的变量而言,它可以在运行时动态解析、绑定要调用的方法。
需要说明都是,动态绑定,必须绑定的是实际存在的方法——否则一样会编译出错。
只有方法才会执行动态绑定,即使成员变量是id类型,成员变量也不会执行动态绑定。
【注意:】如果程序对id类型的指针变量的成员变量进行赋值,程序会编译报错。方法详解:
理解方法:
1. 方法和函数的本质是一样的。
2. 定义方法时,方法不能独立存在,必须定义在类里面。有的方法(+)属于类;有的方法(-)属于实例(对象)
3. 调用方法时,方法也必须有调用者 —— 调用者被称为主调(主语、调用者)
对于+方法,调用者必须是类本身。对于-方法,调用者必须是实例。
猪八戒吃西瓜
[猪八戒 吃:西瓜];
猪八戒.吃(西瓜);
形参个数可变的方法
调用该方法时,可以为该参数传入多个值。
声明方法时,需要使用 ,... 形式来声明个数可变的形参。
实现方法时,需要利用如下来获取调用方法时传入的多个参数:
va_list:这相当于一个指针类型。
va_start: 它是一个函数。va_start(va_list类型变量 , 个数可变的形参名);
va_arg: 它也是一个函数,每次获取一个参数值。
va_end:处理完成后,就使用该函数来关闭va_list类型的变量。
#import "FKComputer.h" @implementation FKComputer - (void) print: (NSString*) content , ... { // 定义一个va_list类型的变量,用于获取程序传入的多个个数可变的参数 va_list argList; // 如果content存在——至少content参数的第一个值要是存在的。 if( content ) { // 首先处理content参数的第一个值 NSLog(@"%@" , content); // 将content参数的参数列表绑定给argList va_start(argList , content); // 程序每调用va_arg一次,即可获取一个参数值。 NSString* arg = va_arg(argList , id); // 如果arg不为nil,就处理该参数——但如果最后一次取出的是nil,循环结束。 while( arg ) { NSLog(@"%@" , arg); arg = va_arg(argList , id); } va_end(argList); // 结束处理。 } } @end
注意:
1. 个数可变的形参只能作为方法的最后一个形参,因此一个方法最多只能声明一个个数可变的形参。
2. 调用个数可变的形参的方法时,程序至少要为个数可变的形参传入一个参数。
变量
全局变量:在源文件范围内声明(不再任何花括号中)。
直接保存在静态存储区的,程序退出时,全局变量才会死亡。
系统会为全局变量自动分配初始值。初始值为广义的0。
局部变量:在函数或方法中声明的。
保存当前的方法或函数栈的,因此随着方法或函数的结束而死亡。
局部变量在程序显式赋初始值之前,局部变量的值是不确定。
成员变量(实例变量):在类后面(接口或实现部分)的一对花括号中。
成员变量会随着对象的allocate而分配内存,成员变量开始出现。
随着对象被回收,成员变量才会被销毁。
实例变量,随着实例的生而生;随着实例的死而死。
——在ARC机制下,如果一个对象没有任何引用变量指向它,那么该对象就会被销毁。
系统会为成员变量自动分配初始值。初始值为广义的0(0、0.0、nil)
实质上,创建对象时,alloc负责分配内存; init就负责执行默认的初始化。
生命期限:
局部变量 < 成员变量 < 全局变量
Object-C所有的成员变量都是实例变量,因此OC只有实例变量,没有类变量。
模拟类变量
用一个static全局变量可模拟类变量。
static全局变量 —— 只能在当前源文件中被访问的全局变量,内部全局变量。
步骤:
(1)在类的实现部分定义一个static全局变量。
(2)为该类声明、并实现一组getter和setter的类方法,用于操作该static全局变量
其中getter方法用于获取全局变量的值;setter方法用于修改全局变量的值。
封装
面向对象的3大特征: 封装、继承、多态。
封装:无处不在。封装包括2方面的含义:
- 把对象的实现细节隐藏在内部。 合理隐藏。
- 把供用户操作的interface暴露出来。 合理暴露。
Object-C实现封装的方式:
通过访问控制符。
↗ @package ↘
@private @public
↘ @protected ↗
@private:彻底隐藏的访问控制符。被@private控制的成员变量,只能在当前类中被访问。 (彻底隐藏)
@package:被@package控制的成员变量,只能在当前类和当前类的同一个映像中被访问。 (部分隐藏:在同一个映像内不隐藏)
@protected:被@protected控制的成员变量,只能在当前类和当前类的所有子类中被访问。 (部分暴露)
@public:被@public控制的成员变量,可以在任意地方被访问。 (彻底暴露)
当前类 与当前类的同一个镜像 当前类的子类 全部范围
@private √ × × ×
@package √ √ × ×
@protected √ × √ ×
@public √ √ √ √
如果成员变量没有使用访问控制符,默认使用@protected修饰。
Object-C的权限控制符,是从当前权限控制符开始,一直管到下一个权限控制符。
一般来说,设计一个类时,推荐做法是:
(1)将成员变量使用private隐藏起来,避免程序直接访问该成员变量。
(2)为该成员变量提供setter、getter方法,setter、getter方法就可添加控制访问逻辑,
从而避免直接修改对象的成员变量的值造成的破坏。
对于方法而言,不能使用@private、@protected、@package、@public控制。
所有在接口部分声明过的方法,都是暴露的方法(相当于public)。
如果只在实现部分实现、未在接口部分声明的方法,都是私有方法(相当于private)。
关于@package的理解
1. 被@package的成员,肯定可以在当前类中被访问。
2. 同一个镜像。 只要和当前类编译成一个文件(包括同一个可执行文件、同一个库文件等),即可称为同一个镜像。
以后在开发APP时,可以只是简单地将成员声明为@package。
合成getter、setter方法
(1)用@property来声明属性。
@property (指示符)NSString* brand;
一条property定义,可以得到3个东西:
(1)得到一个在属性名前面添加_前缀的成员变量——这是成员变量,也是被彻底隐藏的。
(2)getter方法。
(3)setter方法。
如果我们认为系统实现的getter、setter方法不好,程序也可在实现部分重新实现setter、setter方法。
(2) 可选的。如果你希望改变@property合成属性所对应的成员变量名,才需要在实现部分使用@synthesize指令。
@synthesize 属性名; —— 让合成属性对应的成员变量名与属性名完全相同。
@synthesize 属性名 = 新名字; —— 让合成属性对应的成员变量名为新名字。
以上是关于Object-C基础——类与对象的主要内容,如果未能解决你的问题,请参考以下文章