黑马程序员_IOS开发_Objective-C学习笔记_类(对象)

时间:2022-04-09 00:19:22

------- IOS培训、objective-C培训、期待与您交流! ----------

1.面向对象编程基本介绍:

面向对象程序设计(英语:Object-oriented programming,缩写:OOP),指一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的集合,类是对象的模板,它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的安全性、重用性、灵活性和扩展性。

2.面向对象与面向过程

面向过程就是分析出解决问题所需要的步骤,然后基于这些步骤用代码和函数把这些步骤一步一步实现。


面向对象是把构成问题事务分解成各个对象,然后各个对象分别对相关的程序功能做出处理,程序员不用关心对象内部的具体实现,只需要有知道接口代码如何使用即可,大大增强了代码的可复用性。

3.对象 or 类

类是对象的模板,基于类这个模板可以生成大量类似的对象,对象则是对抽象的类的实例化。

4.IOS开发中Objective-C中的类

4.1Objective-C类的结构

扩展名 文件类型说明
.h 头文件/声明文件。头文件包含类、类型、函数和常量声明,类的声明使用关键字@interface@end。UI设计中,storyboard中控件outlet和action是拖到UIViewcontrol的h文件中
.m 实现文件。具有此扩展名的文件可以包含 Objective-C 代码,有时也称为源文件,类的实现使用关键字@implementation@end

NOTE:h文件中的成员函数只是做一个声明,并不对方法进行实现。也就是说,只是说明一下方法名、方法的返回值类型、方法接收的参数类型而已,并不会编写方法内部的代码。这样才能在#import该h文件后,系统就能自动识别我们想输入的东西,有代码提醒。

4.2 方法

 + 表示类方法
 – 表示对象方法


在.h中声明的所有方法作用域都是public类型。

类方法和对象方法的区别在于,类方法不能使用成员变量

使用类方法主要原因有是不需要实例化一个对象也能使用方法,当方法不需要访问类的成员变量的时候就可以考虑把该方法定义为类方法

 

5.创建一个类

5.1声明

IOS开发中所有的类都是从NSObject 继承而来的。类声明以编译器指令 @interface 开始,以 @end 指令结束。类名称后面(以冒号分隔),是父类的名称。在 Objective-C 中,一个类只能有一个父类。

在 @interface 指令和 @end 指令之间,编写属性和方法的声明。这些声明组成了类的公共接口。分号标记每个属性和方法声明的结尾。如果其他的自定函数、常量或数据类型,请将它们的声明放在@interface …@end 块上面。

NOTE:Objective-C中我们通常会在成员变量前面加上 _ (下划线)以和其他变量区分,这里的成员变量作用域有三种类型,分别是@public,@protected,@private,如果没有指定类型,则默认为@protected.

方法声明包含方法类型标识符、返回类型、一个或多个签名关键词,以及参数类型和名称信息。

 

一个方法的名称 (例如:insertObject:atIndex:) 是包括冒号字符在内的所有签名关键词的串联。冒号字符表明有参数存在。在这个例子中,该方法采用两个参数。如果方法没有参数,则省略冒号。

5.2 实现
类实现以 @implementation 指令开始,以 @end 指令结束。中间是方法实现。

下面是例子代码

#import "Person.h"
@implementation Person
- (id)initWithString:(NSString *)name
{
// 插入你的代码
}
+ (Person *)personWithString:(NSString *)name{
// 插入你的代码
}
@end

 

6.实例化对象

#import <Foundation/Foundation.h>
#import "Person.h"
int main(int argc, const char * argv[])
{
 @autoreleasepool {
 Person * person = [[Person alloc]init]; //为对象分配内存空间并初始化

 }
 return 0;
}

 

alloc:会返回分配好内存的Person对象,在等号左边用了一个指向Person类型的指针变量person来接收这个对象,
init:对象初始化

NOTE:你也可以写成下面的这种方式 但是不建议

Person *person = [Person new];

 

 

7.释放对象

在较早的版本之前需要程序员手动内存管理,也就是说释放对象要自己写代码。
[class release] ,class是我们上面实例化的对象。

不过在Xcode5.0,系统默认为启用ARC(全称:Automatic Reference Counting)机制,此时释放对象的任务就交由系统进行处理,如果你使用的是5.0版本,并且想手动释放对象的话,那么可以在Build Settings 里面找到Apple LLVM 5.0 – Language – Objective C的下面把Objective-C Automatic ReferenceCounting 的值设置为NO。

否则你使用 release 的时候Xcode就会报错

8.点语法

下面我们给Person类添加两个方法:

  1. - (int)age;
  2. - (void)setAge:(int)age;

1、上面的age为getter方法,oc习惯把getter方法命名和实例变量名一样。
2、上面的setAge为setter方法,同样习惯于使用set开头,并且后面也与实例变量名相同,而且首字母要大写。

除了上面的方法,OC同时提供了点语法进行访问类方法,请看例子

//使用OC语法,访问age的getter方法、setter方法
[person age];
[person setAge:28];
//使用点语法,访问age的getter方法 person.age person.age = 28;

 

这里要说明的是 person.age 等于 [person age],person.age = 28 等于 [person setAge:28],.语法其实就是访问对象方法的getter和setter方法。至于到底使用哪个方法,取决于你个人使用偏好。

9.构造方法

在Objective-c中,init就是默认的构造方法。

一般来说,我们编写的类可能会在初始化的时候进行对象变量的赋值,所以我们要重构构造方法,示例代码如下:

//声明
- (id)initWithPerson:(int)age;

//实现
- (id)initWithPerson:(int)age {
 self = [super init];
 if(self){
_age = age;
 }
 return self;
}

 

通过上面的代码我们可以看出,构造方法的返回值类型为id,id理解为任何类型的类型。
上面使用了 [super init],这是调用父类的init方法进行初始化,并返回赋值给当前对象self,接下来判断是否为真,如果是则对_age赋值,否则不做任何操作,最后返回当前对象self;

如果我们重构了构造方法,那我们就可以使用如下方式进行创建对象,并初始化了。

Person *person = [Person initWithPerson:28];

 

10.Self关键字

Objective-c中的self代表当前方法的调用者。

- (void)test1(){
 [self test2];
}
+ (void)test2(){
 [Person test1];
 [self test1];
}

 

通过上面的代码我们可以看到不管是在类方法和对象方法中,都可以使用self关键字调用其他方法,并且等于 [Person test1]这种方式。

如果细分一下的话,可以理解为:
类方法:self代表这个类。
对象方法:self代表这个对象。

11.空指针与野指针

11.1空指针
没有存储任何内存地址的指针就称为空指针(NULL指针)
空指针就是被赋值为nil的指针,在没有被具体初始化之前,其值为nil。
下面两个都是空指针:

  1. Student *s1 = NULL; NOTE:NULL是C语言的写法
  2. Student *s2 = nil; NOTE:nil是OC语言的写法

11.2野指针
“野指针”不是NULL指针,是指向”垃圾”内存的指针


11.3示例代码

Person *person = [[Person alloc] init];
person.age = 28;
[person release];
person.age = 20;

 

如果我们在Xcode中运行如上代码会报 person.age = 20;这行的错误,因为上一行已经relase了,这是对象指向的内存地址不可用,也就成了野指针。
当然,如果我们给空指针发消息,则不会报错。

12.@property和@synthesize

我们先写一段代码:

- (int)age;
- (void)setAge:(int)age;

 

上面的代码是age的setter和getter方法声明的简单访问方法,那么有没有一种更方便的方法去做呢?答案就是@property和@synthesize。

在@property中还有其他几个关键字,它们都是有特殊作用的,我把它们分为三类分别是:原子性,访问器控制,内存管理。

12.1原子性
atomic(默认):atomic意为操作是原子的,意味着只有一个线程访问实例变量。atomic是线程安全的至少在当前的访器上我是安全的。它是一个默认的,但是很少使用。它的比较慢,这跟ARM平台和内部锁机制有关。
nonatomic: nonatomic跟atomic刚好相反。表示非原子的,可以被多个线程访问。它的速度比atomic快。但不能保证在多线程环境下的安全性,在单线程和明确只有一个线程访问的情况下广泛使用。


12.2访问器控制
readwrite(默认):readwrite是默认的,表示同时拥有setter和getter。
readonly:readonly 表示只有getter没有setter。

12.3内存管理
retain:使用了retain意味着实例变量要获取传入参数的所有权。具体表现在setter中对实例变量先release然后将参数 retain之后传给它。下面这段代码展示了retain类似的行为:

-(void)setStuName:(NSString *)stuName{
 if (_stuName != stuName)
 {
 [_stuName release];
_stuName = [stuName retain];
 }
}

 

assign(默认):用于值类型,如int、float、double和NSInteger,CGFloat等表示单纯的复制。还包括不存在所有权关系的对象,比如常见的delegate。
strong:是在ARC伴随IOS引入的时候引入的关键字是retain的一个可选的替代。表示实例变量对传入的参数要有所有权关系即强引用。strong跟retain的意思相同并产生相同的代码,但是语意上更好更能体现对象的关系。
weak: weak跟assign的效果相似,不同的是weak在对象被回收之后自动设置为nil。而且weak智能用在iOS 5或以后的版本,对于之前的版本,使用unsafe_unretained。
unsafe_unretained:weak的低版本替代。
copy:copy是为是实例变量保留一个自己的副本。