1. 第一个OC程序
框架(Framework)
和C的Hello不同:
1) 扩展名(后缀名)为.m
2) 使用Foundation框架
3) 使用#import导入头文件:
#import <Foundation/Foundation.h>
#import 会自动处理头文件重复导入问题。
4) 使用NSLog函数输出日志信息
5) 使用clang编译器,并且连接Foundation框架:
clang -framework Foundation xxxx.m (编译时要注意指定Foundation框架)
在Unix/Linux/苹果系统下可执行文件的后缀名可以是任何文件,可以是任意后缀名或没有后缀。
如,a.out==》a.txt (都可以执行!)
总结一个文件扩展名(后缀名):
.c ===》C语言源程序文件
.m ===》OC
.cpp ===》C++
.cc ===》某些Unix系统的C++
.mm ===》Objective C++
.s ===》汇编
.i ===》经过预处理后的源程序
.o ===》编译还没连接的二进制文件
.o、.out (c、c++、Objective-C语言编译后生成的文件)
.a ===》静态库文件
.so ===》Unix/Linux下的动态库文件
.dylib ===》Mac OS/iOS 动态库文件
2. 编译器
C语言标准编译器是: gcc OC早期的编译器使用gcc (gcc不是苹果公司的)
OC现在的编译器:
clang (苹果公司自己开发的,独立的编译器)
LLVM(小的一个语言虚拟机)集成在Xcode中【特点:随时编译,方便Xcode自动随时检查语法错误】
C语言编译器:gcc
OC语言的编译器:clang (由于OC语言兼容所有的C语言语法,所以也可以用clang编译器编译C程序)
3. Xcode写OC程序
只需要在C语言字符串前面加上@符号, 系统就会自动将C语言字符串转换为OC字符串。
4. 面向对象编程
4.0 定义
面向对象编程: 直接使用解决现实生活中问题的办法来解决计算机问题。
4.1 对象
Anything is Object 万物皆对象,现实中,对象是一种客观上的存在。
程序中对象是一片内存空间,这片空间中存放表示对象的数据。
对象:类这种类型的变量
对象中有:
有什么 属性
能干什么 方法
4.1.1 系统中的对象:
一个对象有可能由若干个小对象组成
对象职能单一,一个对象只做自己该做的事
对象们各司其职,各尽所能
对象与对象之间有一定联系,之间用发消息的方式进行工作
这些对象构建成一个运行的系统。
4.1.2 %@打印一个对象(实例对象/类对象):
只要利用%@打印某个对象, 系统内部默认就会调用父类的description方法
打印对象的本质是:打印description方法中的字符串!
4.1.3 匿名对象
有名字的对象:只要用一个指针保存了某个对象的地址, 我们就可以称这个指针为某个对象(称p为TRPerson的对象)
TRPerson *p = [TRPerson new]; p.name = @"张三"; p.age = 22; [p show]; |
没有名字的对象
无论有没有名字, 只要调用new方法都会返回对象的地址
每次new都会新开辟一块存储空间
[TRPerson new].name = @"张三"; [TRPerson new].age = 22; [[TRPerson new] show]; |
4.2 类
类是类型的意思,现实中是一种主观的认识
在计算机中,类是自定义类型,是创建对象的模型(模板)
类就是用于描述对象的共性特征,主要用于描述对象的属性和行为
类中有:属性的定义和方法的定义
4.2.1 类的本质:类其实也是一个对象(类对象),这个对象会在这个类第一次被使用的时候创建。
- 只要有了类对象, 将来就可以通过类对象来创建实例对象
- 实例对象中有一个isa指针, 指向创建自己的类对象
- 类对象中保存了当前对象所有的对象方法
- 当给一个实例对象发送消息的时候,会根据实例对象中的isa指针去对应的类对象中查找
类对象代表类,class类型,对象方法属于类对象
如果消息的接收者是类名,则类名代表类对象
所有类的实例都由类对象生成,类对象会把实例的isa的值修改成自己的地址,每个实例的isa都指向该实例的类对象。
4.2.2 如何获取类对象?
Class c = [类名/实例对象 class];
类对象的应用场景:
- 用于创建实例对象
TRPerson *p3 = [c1 new];
TRPerson *p4 = [[c3 alloc]init];
- 用于调用类方法
[c3 method];//等价于[TRPerson method];
4.2.3 类的启动过程(系统内部自动调用的两个方法:load方法 和 initialize方法)
- load方法:程序一启动就会调用
- 只要程序启动就会将所有类的代码加载到内存中, 放到代码区
- load方法会在当前类被加载到内存的时候调用, 有且仅会调用一次
- 如果存在继承关系, 会先调用父类的load方法, 再调用子类的load方法
- initialize方法:
- 当类第一次被使用的时候就会调用(创建类对象的时候)
- initialize方法在整个程序的运行过程中只会被调用一次, 无论你使用多少次这个类都只会调用一次
- initialize用于对某一个类进行一次性的初始化
- initialize和load一样, 如果存在继承关系, 会先调用父类的initialize再调用子类的initialize
4.3 在OC中定义类和创建对象
4.3.1 定义一个类
分两部分:接口部分,实现部分
1、接口部分
声明类的目的: 告诉系统我们这个类中有哪些属性和方法
@interface 类名 : 父类名 //类开始 //定义属性 //声明方法(相当于声明函数) @end //类结束 |
2. 实现部分
@implementation 类名 //方法的定义(相当于定义函数) @end |
4.3.2 创建对象
创建对象使用alloc,创建好后用一个指针将对象的地址保存起来,以便后面使用。我们把保存对象地址的指针叫引用(Reference)
类名 *引用名 = [类名 alloc];
通过类创建对象
1) 开辟存储空间,通过alloc(new)方法创建对象会在堆内存中开辟一块存储空间
2) 初始化所有属性
3) 返回指针地址
创建对象的时候返回的地址其实就是类的第0个属性的地址
但是需要注意的是: 类的第0个属性并不是我们编写的第一个属性,而是一个叫做isa的属性(isa是一个指针, 占8个字节)
isa属性是系统内部自动帮我们添加的,当你创建一个对象的时候,系统自动生成isa属性
isa是一个指针,占8个字节
isa的作用:会指向创建这个类的那个类
其实类也是一个对象,也就意味着MyClass也是一个对象(类对象)
平时我们所说的创建对象其实就是通过一个 类对象 来创建一个 新的实例对象
类对象是系统自动帮我们创建的,里面保存了当前对象的所有方法
而实例对象是程序自己手动通过alloc(new)来创建的,而实例对象中有一个isa指针就指向了创建它的那个类对象
4.3.2 对象的存储细节
类创建对象,每个对象在内存中都占据一定的存储空间,每个对象都有一份属于自己的单独的成员变量,所有的对象共用类的成员方法。
方法在整个内存中只有一份,类本身在内存中占据一份存储空间。
OC中对象创建 TRPerson *p = [TRPerson new];// 等价于 TRPerson *p = [[TRPerson alloc]init]; 怎么理解这句话: 理解1:定义了一个TRPerson类型的指针变量,指针变量指向新申请的内存空间 理解2:用TRPerson类实例化了(创建了)一个实例对象,对象的名称是p 这里的new做了三件事:
|
4.4 定义属性
1) 在接口部分定义属性:
@property int x; @property double y; @property NSString *name; //对象只能通过引用访问,所以要加*(指针类型) //NSString是OC中的字符串类型,*name代表一个指针,OC语言中字符串类型是一个对象,只能用一个指针来保存一个对象的地址,而不能直接保存一个对象;所有的对象都一样,不能直接用变量来保存对象,只能用一个指针来保存对象的地址!MyClass *obj = [MyClass alloc]; @property NSString *name;//姓名 @property int age;//年龄 @property BOOL gender;//性别 @property double salary;//工资 |
2) 访问对象中的属性:
引用.属性 = 值;
NSLog(@"%d", 引用.属性);
// %@打印字符串对象
NSLog(@“姓名: %@,性别: %@“, self.name,self.gender?@"男":@"女");
4.5 声明和定义方法
1) 在接口部分声明方法
- (返回值类型)方法名;
- (返回值类型)方法名:参数表;
2) 在实现部分定义方法
- (返回值类型)方法名 {
//写具体的实现代码
}
//在OC中方法名会被分解成若干个部分分散在多个参数的前面。 //此方法的方法名是:"setName: age: gender: salary:" - (void)setName:(NSString *)name age:(int)age gender:(BOOL)gender salary:(double)salary; |
3) 调用
通过对象来调用方法
[引用 消息]; //向引用指向的对象发消息(消息的名字应该是方法名),如果引用指向的对象有和这个消息名字相同的方法,就会自动调用此方法。如果没有这个方法,程序崩溃。
4.6 实际开发中类的写法
实际开发中,类的接口部分和实现部分是分开的,接口部分放在头文件中,实现部分放在.m文件中
类名加前缀,防止命名冲突(苹果官方的前缀是两个字母,为了不与官方的重复,开发者一般用3个字母的前缀)
5. 方法(Method)
5.1 概念
本质是函数,在OC中写法和函数不同。
在方法中可以访问属性。
当一个对象收到一个消息时,调用对应的方法。
5.2 分类:
实例方法(instance method): -
类方法(class method): +
在.h中声明的所有方法作用域都是public类型,不能更改。
5.3 实例方法(instance method)
实例(instance)指的是对象。一个类的对象可以被称为这个类的一个实例。
必须通过对象来调用的方法叫实例方法。具体的来说是通过指向对象的引用来调用。
5.4 实例方法的参数
无参、一个参数、多个参数
5.5 方法的返回值
和函数一样
输出一个对象详细信息的两种方法:
5.6 函数和方法的区别
1) 函数属于整个文件, 方法属于某一个类,方法如果离开类就不行
2) 函数可以直接调用, 方法必须用对象或者类来调用
3) 不能把函数当做方法来调用, 也不能把方法当做函数来调用
6. 成员变量、实例变量(instance variable)
6.1 概念
实例就是对象
每个对象(实例)都有一份自己独特的数据和别的对象不同,这些独特的数据会保存在对象的一些特殊变量中,这些变量就是实例变量。
每一个实例都有一份独特的实例变量。实例变量用来记录和保存数据!
有人也叫成员变量
C++ member variable 成员变量
member function 成员函数
6.2 定义成员变量(在OC里也叫实例变量)
//在大括号中声明的变量都为成员变量
{
UIButton *_button;
int age;
id data;
}
成员变量的常用作用域有3种:
- @public 全局都可以访问
- @protected 只能在类内部和子类中访问
- @private 只能在类内部访问
6.3 实例变量和属性的关系
属性的本质:两方法(setter和getter)+ 实例变量
当我们在类中定义一个属性时,编译器会生成以下内容:
1) 保存属性值的实例变量,名字为"_属性名"
2) 修改实例变量值的setter方法,名字为"set属性名",并且属性名的首字母大写
3) 读取实例变量值的getter方法,名字为"属性名"
比如,定义的属性名叫name,生成的实例变量名为"_name",生成的setter方法的名字为:"setName:",生成的getter方法的名字为:"name"
怎么访问实例变量?
在实例方法内(类内部),可以直接访问实例变量。(如:_age=22;)
在实例方法外(类外部),用以下两种方式访问:
1)用->直接进行访问;
如:f->_name = @“张三”; f->_age = 20; (一般不用!)
如果使用,要用@public公开实例变量(实例变量默认是受保护的:@protect),才能用->访问
2)用方法间接访问(setter/getter),属性是访问实例变量的一种方式。
(setter方法可以给实例变量赋值,getter方法可以获取实例变量的值。)
6.4 实际开发中的经验:
一般情况下,很少会定义实例变量,而会大量的定义属性。
在头文件中,尽量不要定义实例变量,而是定义属性。
OC中的实例变量相当于java中的成员变量,OC中经常用实例变量来存数据。
有时候我们会在.m文件中定义实例变量,保存一些私有的数据。也就是说在implementation中定义。
.h文件中的是公开的,.m文件是私有的:
在.h文件中定义的属性(实例变量)是公开的,在.m文件中定义的属性(实例变量)是私有的。
在.h文件中声明和在.m文件中实现的方法是公开的,只在.m文件中实现,未在.h文件声明的方法是私有的。