Objective-C 学习第五天

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

一、

  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段
    数据段
    代码段


    内存.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]];
    
Object-C/Swift官网文档 Object-C/Swift官网文档,包含很多官方链接,应有尽有,最权威的官方文档 立即下载

相关推荐

Object-c资料网站

苹果开发中文站: http://www.cocoachina.com/

理性的幻想 701

object-c学习网站

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/Introduction/Introduction.html

沙漠飞鱼的博客 1689

Objective-C 编程语言官网文档(一)-简介

声明:本文档仅为个人学习过程中顺手翻译之作,方便开发的同胞借鉴参考。如有觉得译的不好不到位的地方,欢迎指正,将及时做出更正 尽量尊重原文档,因为首次Objective-C,有些地方可能直译了没有注意该语言的专有词,希望指正。如需转载,请注明出处 我的编程环境: IDE:XCODE4.3.1 OS: MAC OS X 10....

weixin_30299709的博客 300

objective-c学习推荐网站

这里只推荐一个网站 http://www.objccn.io/ 只能说着上面的文章简直经典,英文原网站: https://www.objc.io/issues/ 我将中文的文章整理成pdf具体下载地址见: http://download.csdn.net/detail/zhouyelihua/9530911

zhouyelihua 1302

Objective-C 10天学习_第五天

小五 1197

Objective-C学习记录】第五天

self,super self理解为C++里的this,当使用self调用方法时,会从当前类中开始查找,没有就依次查找上一级父类。 super就是父类,可以直接调用父类的方法。 +/- OOP中存在公有方法和私有方法,OC中没有,但是用+/-来表示普通方法和静态方法。另外可以用@private来表示私有变量,OC中所有的变量默认都是私有的,方法都是公有的。 深拷贝和浅拷贝 浅拷贝就是增...

weixin_30535167的博客 78

学习Objective-C--第五天

教程详细:       技术:Objective-C    难度:初学者     完成时间:20-30分钟   欢迎来到学习Objective-C系列教程的第五部分,今天我们要看看内存管理,这是特意为新手准备的一个Objective-C的章节哟。大部分脚本语言(如PHP)

坚持就是胜利 1046

黑马程序员——Objective-C 第五天课程学习总结

objective-C 第五天课程学习总结

darewolf 的专栏 512

聚美第五天

今天是我在聚美的第五天,我已经渐渐习惯早出晚归的上班生活了,早上六点半赶两个小时的地铁跟公交,晚上同样回到学校,到寝室就已经是九点钟了。 今天我做了以下工作: 1.修改并提交了case_3_20的代码,测试客户端在售商品状态是否正常。 2.写objective-c截获json数据。 3.学习了json文件的相关知识。 4.学习了http请求及响应的内容及格式。 5. 工作中遇到的问题...

weixin_34342992的博客 103

[Objective-C]第五天

继承的本质,类的本质,SEL,点语法,@property,@synthesize,@property,id类型,动态类型检测,构造方法,动态类型和静态类型

panjiye82的博客 724

Objective - C基础: 第五天 - 1.计数器的基本认识

前言 在我们OC中, 有一个东西是重中之重的知识点, 那就是内存管理, 什么是内存管理呢? 其实内存管理是我们app在运行的时候所使用的内存大小, 在iOS中, 给我们应用设定了一个固定的内存值, 一旦超过这个值, 系统就会给app发送内存警告, 如果这个警告不处理, 那么就会强制关闭应用, 就是我们所说的闪退, 那么内存有多少种呢? 内存其实是分为五种, 分别为堆, 栈, 全局区, 文字常

Cain For iOS的专栏 683

Objective - C基础: 第五天 - 7.autorelease的基本认识

前面我们学了OC内存管理的手动引用计数, 一个alloc, 一个release, 对象的释放由我们自己所决定, 在这里应该会有人问, 这样子运用手动引用计数好累, 有没有简单一点的方法, 答案肯定是有的, 现在我们就来看看第一个简单一点的方法, autorelease方法. 首先我们来看看以前所写的例子: #import @interface Person : NSObject

Cain For iOS的专栏 431

objective-c 第五天 类 对象 方法

1、类1、新建类(类的声明)1、类的声明(定义)//因为是声明,所以是.m文件 //@interface表示类的声明(定义)、Person是类名、NSObject是父类,每个类都需要有继承的父类 @interface Person : NSObject { //下面定义的这2个为这个Person类的属性(也称作全局变量) NSString *_name; NSInteger _age

xh410117的博客 308

Objective - C基础: 第五天 - 3.set方法内存管理

在前面, 我们对OC的内存管理基本上有了一个认识, 也知道了多个对象的内存管理是如何处理, 虽然在前面的多对象内存管理符合内存管理的原则, 其实还有一定的小bug, 今天我们就来看看如何解决这个bug. 例子: #import #import "Car.h" @interface Person : NSObject { int _age; Car *_car

Cain For iOS的专栏 542

Objective - C基础: 第五天 - 6.循环引用

在前面, 我们知道了OC的内存管理以及@property的参数, 其实还有一个叫做循环引用, 其实所谓的循环引用很简单, 就是两个类中, 你包含我, 我包含你, 这个就叫循环引用, 比如下面这个例子: #import #import "Car.h" @interface Person : NSObject @property (nonatomic, retain) Car *car

Cain For iOS的专栏 428
上一篇: Objective-C 学习第四天
下一篇: Objective-C 学习第六天
mazaiting
博客等级 码龄12年 80粉丝 854原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值