• 【使用分类的注意细节 Objective-C语言】


    前言

    使用分类需要注意四个细节:

    一、分类只能增加方法,不能增加属性

    例如,有下面一个分类,这么写是错误的:
    @interface Person (test)
    {
    int _age;
    }
    – (void)haha;
    @end
    这句话会报错:int _age;
    意思是,分类不能写属性!

    二、在分类之中可以写@property ,但是不会自动生成私有属性,也不会自动生成getter、setter的实现,只会生成getter、setter的声明。

    例如,如下这种写法:
    @interface Person (test)
    @property(nonatomic,assign)int age;
    – (void)haha;
    @end
    不会生成_age私有属性,也不会生成- (void)setAge方法,和- (int)age方法。
    如果编译以下的语句,会报发送给实例的消息无法识别,哪个消息呢,[Student setAge:]消息:
    int main()
    {
    Student *s1 = [Student new];
    [s1 setAge:19];//这句话会报错
    return 0;
    }
    怎么办呢,如果你就是想在分类中使用@property声明属性呢,自己在分类的实现文件里写setter、getter方法呗。但是如下写法是错误的:
    @interface Student (test)
    {
    int _age;
    }
    – (void)setAge:(int)age
    {
    _age = age;
    }
    – (int)age
    {
    return _age;
    }
    因为我们刚刚说过,在分类中是不能增加属性的,只能增加方法。
    那怎么办呢,你在Student.h文件中写一个int _age;属性是可以的。
    那为什么你在Student.h里写的属性,在Student+test.m文件里能访问呢,因为是同一个类。
    我记得我们之前讲过,@synthesize可以自动生成私有属性,还可以自动生成setter、getter方法的实现,那在分类的实现文件里写一个这句话,可不可以呢?
    @synthesize age = _age;
    也不行,还是报错:
    @synthesize not allowed in a category’s implementation
    所以,总结:
    在分类之中可以写@property , 但是不会自动生成私有属性,也不会自动生成getter、setter方法的实现,只会生成getter、setter方法的声明。
    所以,你就需要自己写getter、setter的实现,也需要自己定义属性。这个属性,就必须在本类的.h文件当中。

    三、在分类的方法实现当中,不可以直接访问本类的私有属性。但是可以调用本类的getter、setter方法来访问属性。

    例如,这里指的私有属性,不是定义在本类的.h文件中的标记有@private的属性:
    @interface Student : NSObject
    {
    @private
    int _age;
    }
    @end
    这个_age属性,在分类的.m文件里是可以访问的,例如:
    @implementation Student (test)
    – (void)sayHi
    {
    _age = 19;
    }
    @end
    但是,这个定义在本类.m文件中的真私有属性,就访问不了了:
    @implementation Student
    {
    NSString *_name;
    }
    @end

    @implementation Student (test)
    – (void)sayHi
    {
    _name = @“jack”;
    }
    @end
    这样就不行了。。。
    在分类的方法实现中不可以直接访问本类的真私有属性(定义在本类的@implementation之中的属性),但是可以调用本类的getter、setter方法来间接访问属性
    例如:
    @interface Student:NSObject
    @property(nonatomic,strong)NSString *name;
    @end
    这个@property生成的私有属性,是真私有属性,这个_name在分类里面仍然是无法访问的,但是虽然无法直接访问私有属性,但是可以通过点语法,即是调用setter、getter方法间接访问这个私有属性。
    @implementation Student (test)
    – (void)sayHi
    {
    self.name = @“jack”;
    }
    @end
    本类的@property生成的私有属性,只可以在本类的实现中访问,
    分类中不能直接访问私有属性 真私有属性。
    分类可以使用getter、setter 来访问
    例如:[self setName:@“jack”];
    这样是可以的

    四、分类中可以存在和本类同名的方法的 ,当分类中有和本类中同名的方法的时候,优先调用分类的方法,哪怕没有引入分类的头文件,如果多个分类中有相同的方法,优先调用最后编译的分类。在Target编译选项里,Build Phases里的Compile Sources里,可以调整编译顺序,分类中哪1个在下面,哪一个后编译,调用的就是哪1个分类里面的sayHi方法,例如:

    #import

    @interface Student : NSObject

    {

    @private

    int _age;

    }

    - (void)haha;

    @property(nonatomic,strong)NSString *name;

    - (void)sayHi;

    @end

    #import “Student.h”

    @implementation Student

    - (void)haha

    {

    NSLog(@“哈哈。。。”);

    }

    - (void)sayHi

    {

    NSLog(@“我是本类的sayHi方法。。。”);

    }

    @end

    #import “Student.h”

    @interface Student (test)

    @property(nonatomic,assign)int age;

    - (void)hehe;

    - (void)sayHi;

    @end

    #import “Student+itcast.h”

    @implementation Student (test)

    - (void)setAge:(int)age

    {

    _age = age;

    }

    - (int)age

    {

    return _age;

    }

    - (void)sayHi

    {

    self.name = @“jack”;

    _age = 19;

    NSLog(@“我是分类test的sayHi方法。。。”);

    }

    - (void)hehe

    {

    NSLog(@“呵呵。。。”);

    }

    @end

    #import “Student.h”

    @interface Student (test2)

    - (void)test2;

    - (void)sayHi;

    @end

    #import “Student+sb.h”

    @implementation Student (test2)

    - (void)test2

    {

    NSLog(@“嘿嘿。。。”);

    }

    - (void)sayHi

    {

    NSLog(@“我是分类test2中的sayHi方法。。。”);

    }

    @end

    五、举个例子,说一下上面的第三点:

    例如,有一个Person类,有一个真私有属性,int _age;

    #import

    @interface Person:NSObject

    - (void)setAge:(int)age;

    - (void)age;

    @end

    #import “Person.h”

    @implementaion Person

    {

    int _age;

    }

    - (void)setAge:(int)age

    {

    _age = age;

    }

    - (void)age;

    {

    return _age;

    }

    @end

    //为Person类来一个分类:

    #import “Person.h”

    @interface Person (test)

    - (void)tt;

    @end

    #import “Person+test.h”

    @implementation Person (test)

    - (void)tt

    {

    self->_age;//这句话会报错,Person类没有_age属性

    }

    @end

    1、所以,本类中的真私有属性在分类中无法直接访问,指的是声明在本类的@implementation当中的属性,如果是声明在本类的@interface当中的属性,分类可不可以访问,可以。

    2、但是,可以通过本类的setAge方法和age方法,访问真私有属性_age;

    #import “Person.h”

    @interface Person (test)

    - (void)tt;

    @end

    #import “Person+test.h”

    @implementation Person (test)

    - (void)tt

    {

    [self setAge:19];//这样是可以的

    int age = [self age];//这样也是可以的。

    }

    @end

  • 相关阅读:
    MR混合现实情景实训教学系统在商务外语课堂的应用
    js实现对象数组去重
    了解ASEMI代理英飞凌TLE6208-6G其功能和应用的综合指南
    【高等数学】弧微分、渐近线、曲率和曲率半径
    确定谁在往mysql的某张表中写入数据
    01-linux基础-操作系统的学习
    2023年最新一面二面通关王炸java八股文面试题--持续更新
    [2022-11-07]神经网络与深度学习第4章 - 卷积神经网络(part 5)
    服务器io读写较高怎么办?
    SEGGER Embedded Studio IDE移植FreeRTOS
  • 原文地址:https://blog.csdn.net/madoca/article/details/126563223