OC基础--构造方法 id类型
new方法实现原理:
new做了三件事情
1.开辟存储空间 + alloc 方法
2.初始化所有的属性(成员变量) - init 方法
3.返回对象的地址
[Person new]; == [[Person alloc] init];
alloc: 1.开辟存储空间 2.将所有的属性设置为0 3.返回当前实例对象的地址
init: 1.初始化成员变量, 但是默认情况下init的实现是什么都没有做 2.返回初始化后的实例对象地址
注意: alloc返回的地址, 和init返回的地址是同一个地址
构造方法的概念及用途:
在OC中init开头的方法, 我们称之为构造方法
用于初始化一个对象, 让某个对象一创建出来就拥有某些属性和值
重写init方法, 在init方法中初始化成员变量:
重写init方法必须按照苹果规定的格式重写, 如果不按照规定会引发一些未知的错误
1.必须先初始化父类, 再初始化子类
子类继承自父类 那么子类拥有父类所有成员 子类必须调用父类的构造方法对这些成员进行初始化
2.必须判断父类是否初始化成功, 只有父类初始化成功才能继续初始化子类
为了防止父类的初始化方法release掉了self指向的空间并重新alloc了一块空间。还有[super init]可能alloc失败,这时就不再执行if中的语句
3.返回当前对象的地址
super 和 self 指向的是相同的消息接收者 即谁调用就代表谁
- (instancetype)init
{
// 1.初始化父类 只要父类初始化成功 , 就会返回对应的地址, 如果初始化失败, 就会返回nil nil == 0 == 假 == 没有初始化成功
self = [super init];
// 2.判断父类是否初始化成功
if (self != nil) {
// 3.初始化子类 设置属性的值
_age = ;
}
// 4.返回地址
return self;
}
简版:
- (instancetype)init
{
// 注意: 不要把 = 号写为 == 一定要将[super init]的返回值赋值给self
if (self = [super init]) {
// 初始化子类
_age = ;
}
return self;
}
自定义构造方法:
自定义构造方法 其实就是自定义一个init方法:
1.一定是对象方法
2.一定返回id/instancetype
3.方法名称一定以init开头
#import "Person.h" @implementation Person
// 重写init方法
- (instancetype)init{
if (self = [super init]) {
self.name = @"王二小";
self.age = ;
}
return self;
}
// 自定义构造方法 一个类可以有0个或者多个自定义构造方法
- (instancetype)initWithName:(NSString *)name{
if (self = [super init]) {
_name = name;
}
return self;
}
// 自定义构造方法可以有1个或多个参数
- (instancetype)initWithName:(NSString *) name andAge:(int) age{
if (self = [super init]) {
_name = name;
_age = age;
}
return self;
}
@end
自定义构造方法在继承中得表现:
谁声明的成员就由谁去初始化(父类的属性交给父类去处理 子类方法只处理自己独有的属性)
#import "Student.h" @implementation Student
/*
- (instancetype)initWithStudentNO:(NSString *)studentNO andName:(NSString *)name andAge:(int)age{
if (self = [super init]) {
self.name = name;
self.age = age;
self.studentNO = studentNO;
}
return self;
}
*/
- (instancetype)initWithStudentNO:(NSString *)studentNO andName:(NSString *)name andAge:(int)age{
// 由父类的构造方法去初始化 name 和 age 属性
if (self = [super initWithName:name andAge:age]) {
_studentNO = studentNO;
}
return self;
}
@end
调用图解:
自定义类工厂方法:
什么是类工厂方法:
用于快速创建对象的类方法, 我们称之为类工厂方法
类工厂方法中主要用于 给对象分配存储空间和初始化这块存储空间
自定义类工厂方法是苹果的一个规范, 一般情况下, 我们会给一个类提供自定义构造方法和自定义类工厂方法用于创建一个对象
规范:
1.一定是类方法 +
2.方法名称以类的名称开头, 首字母小写
3.一定有返回值, 返回值是id/instancetype
举例:
[[NSString alloc] init];
[NSString string]; [[NSString alloc] initWithString:(NSString *)];
[NSString stringWithString:(NSString *)]; [[NSArray alloc] init];
[NSArray array]; [NSArray alloc] initWithObjects:(id), ..., nil];
[NSArray arrayWithObjects:(id), ..., nil]; // 自定义类工厂方法
+ (instancetype)personWithName:(NSString *)name andAge:(int)age{
Person * person = [[Person alloc] init];
person.name = name;
person.age = age;
return person;
}
自定义类工厂方法在继承中注意点:
由于子类默认会继承父类所有的方法和属性, 所以类工厂方法也会被继承
在类工厂方法中创建对象一定不要使用类名来创建 一定要使用self来创建
self在类方法中就代表类对象 (谁调用当前方法, self就代表谁)
父类的类工厂方法创建实例对象时是使用父类的类名创建的, 如果子类调用父类的类工厂方法创建实例对象,创建出来的还是父类的实例对象
@interface Person : NSObject
+ (id)person;
@end @implementation Person
+ (id)person
{
return [[Person alloc] init];
}
@end @interface Student : Person
@property NSString *name;
@end @implementation Student
@end int main(int argc, const char * argv[])
{
Student *stu = [Student person];// 等效于 [[Person alloc] init] 需要该为 [[self alloc] init]
[stu setName:@"lnj"]; // 报错, 因为Person中没有setName
} // 自定义类工厂方法 使用self 而不是 类名
+ (instancetype)personWithName:(NSString *)name andAge:(int)age{
// Person * person = [[Person alloc] init];
Person * person = [[self alloc] init];
person.name = name;
person.age = age;
return person;
}
id类型:
id是一个数据类型, 并且是一个动态数据类型
既然是数据类型, 所以就可以用来
1.定义变量
2.作为函数的参数
3.作为函数的返回值
id == NSObject * 万能指针
id和NSObject *的区别:
NSObject *是一个静态数据类型
id 是一个动态数据类型
默认情况下所有的数据类型都是静态数据类型
静态数据类型的特点:
在编译时就知道变量的类型,
知道变量中有哪些属性和方法
在编译的时候就可以访问这些属性和方法,
如果是通过静态数据类型定义变量, 如果访问不了属于静态数据类型的属性和方法, 那么编译器就会报错
动态数据类型的特点:
在编译的时候编译器并不知道变量的真实类型, 只有在运行的时候才知道它的真实类型
如果通过动态数据类型定义变量, 如果访问了不属于动态数据类型的属性和方法, 编译器不会报错
- 通过静态数据类型定义变量, 不能调用子类特有的方法
- 通过动态数据类型定义变量, 可以调用子类特有的方法
- 通过动态数据类型定义的变量, 可以调用私有方法
- 弊端: 由于动态数据类型可以调用任意方法, 所以有可能调用到不属于自己的方法, 而编译时又不会报错, 所以可能导致运行时的错误
- 应用场景: 多态, 可以减少代码量, 避免调用子类特有的方法需要强制类型转换
- 为了避免动态数据类型引发的运行时的错误, 一般情况下如果使用动态数据类型定义一个变量, 在调用这个对象的方法之前会进行一次判断, 判断当前对象是否能够调用这个方法
- isKindOfClass
id obj = [Student new];
// isKindOfClass , 判断指定的对象是否是某一个类, 或者是某一个类的子类
if ([obj isKindOfClass:[Student class]]) {
[obj eat];
}
- isMemberOfClass
id obj = [Student new];
if ([obj isMemberOfClass:[Student class]]) {
// isMemberOfClass : 判断指定的对象是否是当前指定的类的实例
[obj eat];
}
instancetype和id的区别:
instancetype == id == 万能指针 == 指向一个对象
id在编译的时候不能判断对象的真实类型
instancetype在编译的时候可以判断对象的真实类型
(一个在编译时不知道真实类型, 一个在编译时知道真实类型)
id可以用来定义变量, 可以作为返回值, 可以作为形参
instancetype只能用于作为返回值
它会进行类型检查,如果创建出来的对象,赋值了不相干的对象就会有一个警告信息,防止出错
注意: 以后但凡自定义构造方法, 返回值尽量使用instancetype, 不要使用id
OC基础--构造方法 id类型的更多相关文章
- 关于void*类型的用法(相当于OC中的id类型)
关于void*类型的用法(相当于OC中的id类型) 1.C++语言在对于void* 类型的使用很特别,因为void* 可以间接引用任何其他数据类型的指针,比如int*.float*甚至抽象数据类型的指 ...
- 六.OC基础--1. id和instancetype类型,2.动态类型检测,3.响应方法,构造方法,4.重写构造方法,5.自定义构造方法
1. id和instancetype类型, id和instancetype类型区别: 1. id和instancetype都可以用来作为方法的返回值 2. id可以用来定义类型,instancetyp ...
- OC基础--构造方法
OC语言中类的构造方法学了两种: 一.方法一:[类名 new] 例:[Person new] 缺点:可扩展性不强,假如在Person类中有_age 成员变量,在初始化时想让_age 中的值为20,ne ...
- oc 中的id类型与类型转换
id是oc语言中一个独特的数据类型.一种通用对象类型.可以转换为任何数据类型,即id类型的变量可以存放任何数据类型的对象. 使用示例: Animal * dog = [[Dog alloc]init] ...
- OC基础笔记目录
OC基础(1) Objective-C简介 OC和C对比 第一个OC程序 面向对象思想 OC基础(2) 类与对象 类的设计 第一个OC类 对象方法的声明和实现 类方法的声明和实现 OC基础(3) 对象 ...
- 张超超OC基础回顾_05 property修饰符,id类型,instancetype。。。
一.property 如果给一个属性同时提供了getter/setter方法, 那么我们称这个属性为可读可写属性 如果只提供了getter方法, 那么我们称这个属性为只读属性 如果只提供了setter ...
- OC基础6:多态、动态类型和动态绑定
"OC基础"这个分类的文章是我在自学Stephen G.Kochan的<Objective-C程序设计第6版>过程中的笔记. 1.关于SEL类型的数据: (1).SEL ...
- OC的特有语法-分类Category、 类的本质、description方法、SEL、NSLog输出增强、点语法、变量作用域、@property @synthesize关键字、Id、OC语言构造方法
一. 分类-Category 1. 基本用途:Category 分类是OC特有的语言,依赖于类. ➢ 如何在不改变原来类模型的前提下,给类扩充一些方法?有2种方式 ● 继承 ● 分类(Categor ...
- 五.OC基础--1.多态,2.类对象,3.点语法,4.@property&@synthesize,5.动态类型,内省(判断对象是否遵循特定的协议,以及是否可以响应特定的消息)
五.OC基础--1.多态, 1. 多态概念,定义:多态就是某一类事物的多种形态: 表现形式: Animal *ani = [Dog new]; 多态条件:1.有继承关系 2.有方法的重写 2.多态代码 ...
随机推荐
- JavaScript精要(系列)
JavaScript精要系列 JavaScript精要(六):JavaScript DOM节点和文档类型 JavaScript精要(五):JavaScript数组类型 JavaScript精要(四): ...
- 关于ES3、ES5、ES6以及ES7所有数组的方法(api)的总结
起因:工作用经常用到操作数组的方法,这里进行一下总结,我尽量以简洁的语言概括每个方法(api)的作用.如果您想快速定位,可以Control+F 然后搜相应的方法即可定位 :) ES3的数组方法 joi ...
- 命令行用sublime打开当前目录
执行 ln -s "/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl" subl 就可以在命令行用 ...
- TCP/IP协议学习(七) 基于C# Socket的Web服务器---动态通讯实现
目录 (1).基于Ajax的前端实现 (2).Web服务器后端处理 一个完整的web服务器,不仅需要满足用户端对于图片.文档等资源的需求:还能够对于用户端的动态请求,返回指定程序生成的数据.支持动态请 ...
- TCP/IP协议学习(五) 基于C# Socket的C/S模型
TCP/IP协议作为现代网络通讯的基石,内容包罗万象,直接去理解理论是比较困难的:然而通过实践先理解网络通讯的理解,在反过来理解学习TCP/IP协议栈就相对简单很多.C#通过提供的Socket API ...
- static修饰的静态内部类
Java里面static一般用来修饰成员变量或函数.但有一种特殊用法是用static修饰内部类,普通类是不允许声明为静态的,只有内部类才可以.被static修饰的内部类可以直接作为一个普通类来使用,而 ...
- 使用JS实现轮播图的效果
其中的一些css样式代码就省略了,下面只把结构层html.行为层js的代码展示出来 ,看代码说事. 一.简单的轮播图 <div class="box" id="bo ...
- .net 导出Excel功能
将DataSet对象导出成Excel文档 一.不带格式控制 void btnExport_Click(object sender, EventArgs e) { IList<string> ...
- linux 记录用户操作记录日志
####################################################################################historyUSER_IP=$ ...
- Android布局整理Relative/Linear
1.RelativeLayout布局 android:layout_centerHorizontal 水平居中 android:layout_centerVertical 垂直居中 android:l ...