Objective-C 学习第五天

简介: 一、创建一个对象,内存是如何分配1). 子类对象中有自己的属性和所有父类的属性2). 代码段中每一个类都有一个isa指针,这个指针指向它的父类.结构体与类相同点: 都可以将多个数据封装为1个整体 struct Data{ ...

一、

  1. 创建一个对象,内存是如何分配
    1). 子类对象中有自己的属性和所有父类的属性
    2). 代码段中每一个类都有一个isa指针,这个指针指向它的父类.

  2. 结构体与类

    1. 相同点: 都可以将多个数据封装为1个整体
        struct Data{
            int year;
            int month;
            int day;
        }
    
        @interface Data : NSObject{
            int year;
            int month;
            int day;
        }
    

    2). 不同点:
    a. 结构体只能封装数据,而类不仅可以封装数据还可以封装行为
    b. 结构体变量分配在栈空间(前提是局部变量),而对象分配在堆空间.
    栈空间相对较小,但是访问效率高;
    堆空间较大, 访问效率低.

    3). 应用场景:
    a. 如果表示的实体不仅有数据还有行为,只能使用类
    b. 如果表示的实体只有数据, 没有行为,视属性多少而定.如果属性只有几个,就定义为结构体; 如果属性较多,就定义为类.

  3. 类的本质


    BSS段
    数据段
    代码段


    img_7f9ec2faf56dbd87463f99d801877a39.png
    内存.png

    代码段是用来存储代码的.
    类加载,当类第一次被访问的时候,这个类就会被加载到代码段存储起来.
    类一旦被加载,是不会被回收的,除非程序结束.

    1). 任何存储在内存中的数据都有1个数据类型.
    2). 在代码段存储类的步骤
    a. 先在代码段中创建Class对象, Class是Foundation框架中的一个类
    b. 将类的信息存储在这个Class对象之中
    Class对象至少有三个属性:
    类名/属性s/方法s
    存储类的这个Class对象,叫做类对象
    所以存储类的类对象也有一个isa指针

  4. 类对象使用
    1). 调用类的类方法class,就可以了得到存储类的类对象的地址
    Class c1 = [Person class];
    2). 调用对象的对象方法,就可以了得到这个对象所属的类的Class对象的地址.
    Person p1 = [Person new];
    Class c2 = [p1 class];
    注意: 声明Class指针的时候,不需要加
    ,因为typedef的时候就已经加*了.
    3). 拿到存储类的类对象以后
    Class c1 = [Person class];
    c1对象就是Person类, c1 完全等价于Person
    a. 使用类对象来调用类的类方法,
    Class c1 = [Person class];
    [c1 sayHi] 等价于 [Person sayHi];
    b. 创建对象
    Class c1 = [Person class];
    [c1 new] 等价于 [Person new];

    1. 注意: 使用类对象,只能调用类的类方法,不能调用对象方法
  5. SEL全程 select 选择器
    SEL是一个数据类型. 要在内存中申请空间存储数据,SEL其实是一个类,SEL对象用来存储一个方法
    1). 类是以Class对象的形式存储在代码段中
    类名: 存储这个类的类名.NSString
    a. 如何将方法存储在类对象之中
    a). 先创建一个SEL对象
    b). 将方法的信息存储在这个SEL对象之中
    c). 再将这个SEL作为Class对象的属性
    2). 拿到存储方法的SEL对象
    a. 因为SEL是typedef类型的,在自定义的时候已经加了,所以声明SEL指针的时候不需要加
    b. 取到存储方法的SEL对象
    SEL s1 = @selector(方法名);
    示例:
    SEL s1 = @selector(sayHi);
    3). 调用方法的本质
    Person p1 = [Person new];
    [p1 sayHi];
    内部原理:
    a. 先拿到存储sayHi方法的SEL对象,也就是拿到sayHi方法的SEL数据,SEL消息
    b. 将这个SEL消息发送给p1对象
    c. p1对象接收到这个SEL消息之后,就知道调用方法
    d. 根据对象的isa指针找到存储类的类对象
    e. 如果找到这个类对象之后,搜寻是否有和传入的SEL数据相匹配的,如果有,就执行,如果乜有就找父类,知道NSObject
    OC最重要的1个机制: 消息机制
    调用方法的本质其实就是为对象发送SEL消息
    [p1 sayHi]: 为p1对象发送一个sayHi方法
    4). 手动为对象发送SEL消息
    a. 先得到方法的SEL数据
    b. 把这个SEL数据发送给p1对象
    - (id)performSelector:(SEL)aSelector;
    示例:
    Person *p1 = [Person new]; SEL s1 = @selector(sayHi); [p1 performSelector:sel];
    c. 调用一个对象的方法有两种
    a). [对象名 方法名];
    b). 手动的为对象发送SEL消息
    5). 注意事项:
    a. 如果方法名有参数 那么方法名是带了参数的
    b. 如果方法有参数,就调用另外一个方法
    - (id)performSelector:(SEL)aSelector withObject:(id)object;
    c. 如果方法有多个参数,就将对象传递过去

  6. 点语法
    OC中也可以使用点语法来访问对象的属性,和Java,C#是完全不一样的.
    1). 使用点语法访问对象的属性.
    语法:对象名.去掉下划线的属性名
    p1.name = @"jack";这个时候就会将@"jack"赋值给p1对象的_name属性; NSString *name = p1.name;把p1对象的_name属性值取出来
    2). 点语法原理
    p1.age = 18;
    这句话的本质并不是把18直接赋值给p1对象的_age属性,点语法在编译器编译的时候,会将点语法转换为调用setter/getter的代码
    a. 当使用点语法赋值的时候,这个时候编译器会将点语法转换为调用setter方法的代码.
    对象名.去掉下划线的属性名 = 数据;
    转换为:
    [对象名 set去掉下划线的属性名首字母大写] = 数据;
    p1.age = 10相当于[p1 setAge:10];
    b. 当使用点语法取值的时候,这个时候编译器会将点语法转换为调用getter方法的代码.
    对象名.去掉下划线的属性名;
    转换为:
    [对象名 去掉下划线的属性名];
    int age = p1.ag相当于[p1 age];
    3). 注意:
    a. 在getter/setter方法中慎用点语法, 因为有可能会造成无线递归导致程序崩溃
    b. 点语法在编译器编译的时候会转换为setter/getter方法的代码.
    如果我们的setter和getter方法名不符合规范,那么就会报错.
    c. 如果属性没有封装getter/setter是无法使用点语法的

  7. @property
    1). 写一个类
    a. 写属性
    b. 声明属性的getter/setter
    c. 再实现getter/setter
    2). @property
    a. 作用: 自动生成getter/setter的声明,应该写在@interface声明之中
    b. 语法:
    @property 数据类型 变量名;
    @property int age;
    c. 原理:
    编译器在编译的时候,会根据@property生成getter/setter方法的实现
    @property 数据类型 名称;
    生成为:
    - (void)set首字母大写的名称:参数;
    - (数据类型)名称;
    示例:
    @property int age;
    - (void)setAge:(int)age;
    - (int)age;
    3). 使用@property注意:
    a. @property的类型和属性的类型一致.
    @property的名称和属性名称一致(去掉下划线).
    b. @property的名称决定了生成getter和setter方法的名称.
    @property的数据类型决定了生成的getter和setter方法的数据类型.
    c. @property只是生成getter和setter方法的声明,实现要自己写.

  8. @synthesize
    1). 作用: 自动生成getter/setter方法的实现,应该写在类的实现当中
    2). 语法:
    @synthesize @property名称;

        // 声明
        @interface Person : NSObject{
            int _age;
        }
        @property int age;
        @end;
    
        // 实现
        @implementation Person
        @synthesize age;
        @end
    

    3). @synthesize做的事情
    a. 生成一个真私有的属性,属性的类型和@synthesize对应的@property类型一致,属性的名字和@synthesize对应的@property名字一致.
    b. 自动生成setter方法的实现
    实现的方式:将参数直接赋值给自动生成的那个私有属性.并且没有做任何的逻辑验证
    c. 自动生成getter方法的实现
    4). 希望@synthesize不要自动生成私有属性,getter/setter的实现中操作我们写好的属性.
    a. 语法
    @synthesize @property 名称 = 已经存在的属性名;
    示例: @synthesiez age = _age;
    a). 不会再生成私有属性
    b). 直接生成getter/setter的实现.
    setter实现: 把参数的值直接赋值给指定的属性.
    getter的实现: 直接返回指定的属性的值.
    5). 注意:
    a. 如果直接写一个@synthesize
    @synthesize name;
    b. 如果指定操作的属性.
    @synthesize name = _name;
    c. 生成的setter方法实现中没有任何逻辑验证,生成的getter方法的实现中式直接返回属性的值
    d. 如果要有自己的逻辑验证,需要自己实现.
    6). 批量声明
    a. 如果多个@property的类型一致,可以批量声明.
    @property float height,weight;
    b. @synthesize批量写, @synthesize name = _name, age = _age;

  9. @property增强
    1). 从4.4之后, 对@property做了增强.
    2). 只需要写一个@property,编译器就会自动的生成私有属性、生成getter/setter的声明、生成getter/setter的实现.
    3). @property NSString *name;
    a. 自动的生成一个私有属性, 属性的类型和@property类型一致,属性的名称和@property的名称一致,属性的名称自动的加下划线
    b. 自动的生成getter/setter的声明
    c. 自动的生成getter/setter的实现
    setter的实现直接将参数的值赋值给自动生成的私有属性.
    getter的实现直接返回私有属性的值.
    4). 使用注意
    a. @property的类型一定要和属性的类型一致,名称要和属性的名称一致
    b. 可以批量声明

  10. 动态类型和静态类型
    1). OC是一门若语言,编译器在编译的时候,检查的时候没有那么严格.
    优点:灵活
    缺点:太灵活

    强类型的语言: 编译器在编译的时候做语言检查的时候,非常严格.
    2).
    a. 静态类型:指的是一个指针指向的对象是一个本类对象,
    b. 动态类型: 指的是一个指针指向的对象不是本类对象。
    3). 编译检查:编译器在编译的时候,能不能通过1个指针去调用指针指向的对象的方法.
    判断原则:看这个指针所属的类型之中是否有这个方法,如果有就认为可以调用,编译通过,如果没有就报错。
    4). 运行检查: 编译检查只是骗过了编译器,但是这个方法究竟能不能执行还不一定,运行时会去检查对象当中是否有这个方法

  11. NSObject是OC中所有类的基类,根据LSP NSObject指针就可以指向任意的OC对象,所有NSObject指针时一个万能指针.可以指向任意的OC对象.
    缺点: 如果要调用指向的子类对象的独有的方法,就必须要就类型的强转。

  12. id指针是一个万能指针,可以指向任意的OC对象.
    1). id是一个typedef类型,在定义的时候已经加了,所以声明id指针的时候就不需要加
    2). id指针是一个万能指针,任意的OC对象都可以指。
    3). NSObject与id
    相同点: 万能指针,都可以指向任意的OC对象
    不同点: 通过NSObject指针去调用对象的方法的时候,编译器会做编译检查.通过id类型的指针去调用对象方法的时候,不会报错.
    4). 注意:id指针只能调用方法,不能使用点语法

  13. instancetype
    1). 如果方法的返回值是instancetype代表方法的返回值是当前类的对象.
    // 声明 - (instancetype)person; // 实现 - (instancetype)person{ return [self new]; }
    建议:
    a. 如果方法内部是在创建当前类的对象,不要写死成类名[类名 new],而是用self代替类名
    b. 如果方法的返回值是当前类的对象,也不要写死了,而是写instancetype.
    2). id和instancetype的区别
    a. instancetype只能作为方法的返回值,不能在其他地方使用,id既可以声明指针变量也可以作为参数,也可以作为返回值
    b. instancetype是一个有类型的代表当前类的对象,id是一个无类型的指针,仅仅是一个地址,没有类型的指针

  14. 构造方法
    1). 创建对象
    类名 *指针名 = [类名 new];
    new 实际上是个类方法.
    new方法作用:
    -> 创建对象
    -> 初始化对象
    -> 把对象的地址返回
    new方法的内部,其实是先调用alloc方法,再调用init方法
    alloc方法是一个类方法,那个类调用这个方法就创建哪个类对象
    init是一个对象方法,初始化对象
    创建对象的完整步骤:
    应该是先使用alloc创建一个对象,然后使用init初始化这个对象
    Person *p1 = [Person new];
    完全等价于
    Person *p1 = [[Person alloc] init];

    2). init方法
    作用: 初始化对象,为对象的属性赋初始值,这个init方法我们叫做构造方法
    init方法做到的事情: 初始化对象.
    3). 想要让创建对象的属性的默认值不是nil,NULL,0,那么我们可以重写init方法.按照我们自己的想法为对象的属性赋值.
    重写init方法规范:
    a. 必须先调用父类的init方法.
    b. 调用方法初始化对象失败返回nil
    c. 判断父类是否初始化成功,如果不是nil,说明初始化成功
    d. 如果初始化成功,就初始化当前对象的属性
    e. 最后返回self

        - (instancetype)init{
            // 初始化父类属性的值
            self = [super init];
            if(self){
                self.name = @"jack";
            }
            return self;
        }
    

    4). 自定义构造方法
    规范:
    a. 返回值必须是instancetype
    b. 自定义构造方法开头必须是initWith
    c. 方法的实现与init的要求一样

        - (instancetype)initWithName:(NSString *)name{
            // 初始化父类属性的值
            self = [super init];
            if(self){
                self.name = name;
            }
            return self;
        }
    
        Dog *d1 = [[Dog alloc] initWithName:@"小黄"];
    
  15. 动态类型检测
    1). 判断指针指向的对象当中,指定的方法是否可以调用

        Person *p1 = [Person new];
        BOOL isHave = [p1 responseToSelector:@selector(setName:)];
    

    2). 判断类方法是否可以调用
    3). 判断对象是否为指定类对象或者子类对象

        NSMutableString *str = [NSMutableString class];
        BOOL res = [str isKindOfClass:[NSString class]];
    

    4). 判断对象是否为指定类的对象(不包括子类)

        NSMutableString *str = [NSMutableString class];
        BOOL res = [str isMemberOfClass:[NSString class]];
    

    5). 判断指定的类是否为另外一个类的子类

        BOOL res = [NSMutableString isSubclassOfClass:[NSString 
        class]];
    
目录
相关文章
|
存储 Java 程序员
C++ 开发者快速学习 Objective-C 语言核心语法
本文将讨论 Objective-C 语言的核心语法。这部分开始详述一些具体的语法。正如你期待的一样,涉及到了定义和类。
253 0
|
存储 C语言 iOS开发
Objective-C 学习第一天
一、基础语法 OC相对于C a. 在C的基础上新增了面向对象的语言 b. 将C的复杂、繁琐的语法封装的更为简单 c. OC完全兼容C语言 OC程序的源文件后缀名是.m m代表message 代表OC当中最重要的一个机制 消息机制 C程序的源文件的后缀名.c main函数仍然是OC程序的入口和出口 int类型的返回值代表程序的结束状态 main函数的参数: 仍然可以接收用户在运行程序的时候传递数据给程序, 参数也可以不要 #import指令 1). 以#号开头,是1个预处理指令 2). 作用: 是#include指令的增强版。
841 0
|
存储 iOS开发 C语言
Objective-C 学习第二天
一、 对象在内存中的存储 内存中的五大区域 栈 存储局部变量 堆 程度员手动申请的字节看空间 malloc calloc realloc函数 BSS段 存储未被初始化的全局变量, 静态变量 数据段(常量区) 存储已被初始化的全局、静态变量、常量数据 代码段 存储代码 存储代码程序 类加载 a.
749 0
|
存储 iOS开发
Objective-C 学习第三天
封装 一、 什么是错误 一般情况下,错误是指源代码不符合语法规范,然后编译报错 后果: 程序无法编译 什么是Bug? 程序可以编译、链接、执行,但是程序执行的结果不是我们预想的。
917 0
|
存储 iOS开发
Objective-C 学习第四天
一、 Xcode文档的安装 1). Xcode文档提供了很多框架, 框架当中有很多类和函数, 提供的一些数据类型. 2). Xcode文档需要单独安装.
923 0
|
存储 安全 iOS开发
Objective-C 学习第六天
一、 内存管理 内存的作用: 存储数据. 1). 如何将数据存储到内存之中 声明1个变量,将这个数据存储进去 2). 当数据不再被使用的时候,占用的内存空间如何被释放 内存中的五大区域 栈:局部变量,当局部变量的作用域被执行完毕之后,这个局部变量就会被系统立即回收.
982 0
|
存储 对象存储 iOS开发
Objective-C 学习第七天
一、 自动释放池的原理 存入到自动释放池中的对象,在自动释放池销毁的时候,会自动调用储存在该自动释放池中的所有对象的release方法. 可以解决的问题: 将创建的对象,存入到自动释放池之中,就不再需要手动的release这个对象了,因为池子销毁的时候,就会自动的调用池中所有的对象release.
861 0
|
存储 iOS开发
Objective-C 学习第八天
一、延展 延展: Extension 1). 是一个特殊的分类,所以延展也是类的一部分 2). 特殊之处: a. 延展这个特殊的分类没有名字 b. 只有声明没有实现,和本类共享一个实现 延展的语法 语法: @interface 本类名 () @end 没有实现,和本类共享一个实现.
854 0
|
存储 iOS开发 对象存储
Objective-C 学习第九天
一、 框架: 系统或者第三方事先写好的写很牛X功能的类,把这些类交给我们使用,这些类的集合就叫框架. Foundation框架: 是一个包,有很多类和函数,定义了一些数据类型.
946 0
|
存储 对象存储 iOS开发
Objective-C 学习第十天
一、NSDictionary NSArray和NSMutableArray数组 存储数据特点:每个元素紧密相连,并且每个元素中都是直接存储的值. 缺点:数组元素下标不固定,都有可能发生变化,无法通过下标来唯一确定数组中的元素.
809 0