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类型的更多相关文章

  1. 关于void*类型的用法(相当于OC中的id类型)

    关于void*类型的用法(相当于OC中的id类型) 1.C++语言在对于void* 类型的使用很特别,因为void* 可以间接引用任何其他数据类型的指针,比如int*.float*甚至抽象数据类型的指 ...

  2. 六.OC基础--1. id和instancetype类型,2.动态类型检测,3.响应方法,构造方法,4.重写构造方法,5.自定义构造方法

    1. id和instancetype类型, id和instancetype类型区别: 1. id和instancetype都可以用来作为方法的返回值 2. id可以用来定义类型,instancetyp ...

  3. OC基础--构造方法

    OC语言中类的构造方法学了两种: 一.方法一:[类名 new] 例:[Person new] 缺点:可扩展性不强,假如在Person类中有_age 成员变量,在初始化时想让_age 中的值为20,ne ...

  4. oc 中的id类型与类型转换

    id是oc语言中一个独特的数据类型.一种通用对象类型.可以转换为任何数据类型,即id类型的变量可以存放任何数据类型的对象. 使用示例: Animal * dog = [[Dog alloc]init] ...

  5. OC基础笔记目录

    OC基础(1) Objective-C简介 OC和C对比 第一个OC程序 面向对象思想 OC基础(2) 类与对象 类的设计 第一个OC类 对象方法的声明和实现 类方法的声明和实现 OC基础(3) 对象 ...

  6. 张超超OC基础回顾_05 property修饰符,id类型,instancetype。。。

    一.property 如果给一个属性同时提供了getter/setter方法, 那么我们称这个属性为可读可写属性 如果只提供了getter方法, 那么我们称这个属性为只读属性 如果只提供了setter ...

  7. OC基础6:多态、动态类型和动态绑定

    "OC基础"这个分类的文章是我在自学Stephen G.Kochan的<Objective-C程序设计第6版>过程中的笔记. 1.关于SEL类型的数据: (1).SEL ...

  8. OC的特有语法-分类Category、 类的本质、description方法、SEL、NSLog输出增强、点语法、变量作用域、@property @synthesize关键字、Id、OC语言构造方法

    一. 分类-Category 1. 基本用途:Category  分类是OC特有的语言,依赖于类. ➢ 如何在不改变原来类模型的前提下,给类扩充一些方法?有2种方式 ● 继承 ● 分类(Categor ...

  9. 五.OC基础--1.多态,2.类对象,3.点语法,4.@property&@synthesize,5.动态类型,内省(判断对象是否遵循特定的协议,以及是否可以响应特定的消息)

    五.OC基础--1.多态, 1. 多态概念,定义:多态就是某一类事物的多种形态: 表现形式: Animal *ani = [Dog new]; 多态条件:1.有继承关系 2.有方法的重写 2.多态代码 ...

随机推荐

  1. 监狱3D指纹门禁系统解决方案

    由于监狱的行业特殊性,其安全性对社会的安定团结具有重大影响力.因此,采用高新技术来建立监狱的安全屏障,提高监狱安全的规范化.科学化管理水平.用高效的技术防范手段对监狱安全实行事前的主动的防范,保障社会 ...

  2. 在ionic/cordova中使用Form模型验证(w5cValidator)

    在构建ionic项目过程中,当我们创建一个类似表单提交的页面时,可能会对用户的输入内容做某些规则验证,通过后再执行提交处理. 在验证的过程中,为了提供较好的用户体验,可能希望有类似于jquery Va ...

  3. Ubuntu 和 Redhat / Fedora 服务管理命令对比表(附Fedora16新的服务管理工具systemctl )

    以 apache/httpd 服务作为例子 任务 Red Hat / Fedora Ubuntu Ubuntu (with sysv-rc-conf or sysvconfig) 立即启动/停止某服务 ...

  4. npm相关

    npm list -g --depth 0 : -g 列出所有全局模块,--depth 使列表只列出简略信息,如包名.版本号

  5. activity通过onActivityResult间数据交互

    首先要创建2个activity 分别为MainActivity和OneActiivity MainActivity代码如下: package com.tp.soft.app; import andro ...

  6. C#常用错误

    解决方法: 在配置文件连接数据库设置后加 MultipleActiveResultSets=true; <add key="ConnectionString" value=& ...

  7. Linux时间设置及同步

    Linux系统安装时选择的UTC时间是国际标准时间,而中国处于UTC+8时区,因此安装系统时不要选择UTC时区. 还有就是Linux有两个时钟: 1.Bios时钟及硬件时间 2.Kernel时钟及系统 ...

  8. 【51nod】区间求和

    LYK在研究一个有趣的东西. 假如有一个长度为n的序列,那么这个序列的权值将是所有有序二元组i,j的 Σaj−ai 其中1<=i<j<=n. 但是这个问题似乎太简单了. 于是LYK想 ...

  9. miniui

    //android提供了一个库minui用于简单的UI输出,源码在bootable/recovery/minui中, //gr_init()和gr_font_size()为minui库提供方法,gr_ ...

  10. [阅读笔记]Zhang Y. 3D Information Extraction Based on GPU.2010.

    1.立体视觉基础 深度定义为物体间的距离 视差定义为同一点在左图(reference image) 和右图( target image) 中的x坐标差. 根据左图中每个点的视差得到的灰度图称为视差图. ...