文档章节

iOS分类不能添加属性原因的探索

hanbing94
 hanbing94
发布于 2017/05/08 12:18
字数 949
阅读 6
收藏 0

最近跟人交流时,提到一个问题,说iOS分类中不能添加属性。这里探讨一下不能添加的原因和添加的方法。
首先,创建一个person类,代码如下:

XGPerson.h

#import <Foundation/Foundation.h>

@interface XGPerson : NSObject
/// 年龄
@property (nonatomic, copy) NSString *age;
/// 性别
@property (nonatomic, copy) NSString *sex;

- (void)text1;

@end

XGPerson.m

#import "XGPerson.h"

@implementation XGPerson

- (void)text1 {
    NSLog(@"%s",__func__);
}

- (void)text2 {
    NSLog(@"%s",__func__);
}
@end

在控制器里获取并打印该类的成员变量、属性和方法,代码如下:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    // 获取成员变量
    unsigned int ivarCount = 0;
    Ivar *ivars = class_copyIvarList([XGPerson class], &ivarCount);
    for (int i = 0; i < ivarCount; i++) {
        Ivar ivar = ivars[i];
        NSLog(@"第%d个成员变量:%s",i,ivar_getName(ivar));
    }
    free(ivars);
    // 获取属性
    unsigned int propertyCount = 0;
    objc_property_t *propertyList = class_copyPropertyList([XGPerson class], &propertyCount);
    for (int i = 0; i < propertyCount; i++) {
        objc_property_t property = propertyList[i];
        NSLog(@"第%d个属性:%s",i,property_getName(property));
    }


    // 获取方法列表
    unsigned int methodCount = 0;
    Method *methods = class_copyMethodList([XGPerson class], &methodCount);
    for (int i = 0; i < methodCount; i++) {
        Method method = methods[i];

        NSLog(@"第%d个方法:%s",i, sel_getName(method_getName(method)));
    }

}

此时控制台输出如下:

没有分类时.png


这里需要提出的是,平时使用@property的时候,系统会自动生成带“_”的成员变量和该变量的setter和getter方法。也就是说,属性相当于一个成员变量加getter和setter方法。那么,在分类里使用@property会是什么样子呢,下面来创建一个分类:
XGPerson+height.h

#import "XGPerson.h"

@interface XGPerson (height)

@property (nonatomic, copy) NSString *height;

@end

XGPerson+height.m

#import "XGPerson+height.h"

#import <objc/runtime.h>

@implementation XGPerson (height)


@end

如果像上面一样只在.h文件里声明height,那么.m文件里会出现两个警告,意思是说没有实现setter和getter方法。

警告.png

此时在控制器里执行touchesBegan方法,控制台输出如下:

有分类未实现存取方法.png


可以看到,此时person类里并没有添加带“_”的成员变量,也没有实现setter和getter方法,只是在属性列表里添加了height属性。并且此时如果在控制器里调用self.height,程序运行时会报错,显示找不到该方法。实现一下person分类里的两个方法:
XGPerson+height.m

#import "XGPerson+height.h"

#import <objc/runtime.h>

@implementation XGPerson (height)

 - (NSString *)height {

 }

 - (void)setHeight:(NSString *)height {

 }

@end

此时在控制器里执行touchesBegan方法,控制台输出如下:

有分类实现存取方法.png

可以看到即使实现了setter和getter方法,也仍然没有添加带“”的成员变量,也就是说,在setter和getter方法里仍然不能直接访问以下划线开头的成员变量,因为在分类里用@property声明属性时系统并没有添加以“”开头的成员变量。此时要达到添加的目的可以使用运行时的关联对象。示例代码如下:
XGPerson+height.m

#import "XGPerson+height.h"

#import <objc/runtime.h>

@implementation XGPerson (height)



 - (NSString *)height {
 return objc_getAssociatedObject(self, @"height");
 }


 - (void)setHeight:(NSString *)height {
 objc_setAssociatedObject(self, @"height", height, OBJC_ASSOCIATION_COPY_NONATOMIC);
 }

@end

当然也可以在setter和getter方法里访问该类其他的属性,比如在UIView的分类的里添加x、y属性,可以直接返回self.frame.origin.x和self.frame.origin.y。

总结

在分类里使用@property声明属性,只是将该属性添加到该类的属性列表,并声明了setter和getter方法,但是没有生成相应的成员变量,也没有实现setter和getter方法。所以说分类不能添加属性。但是在分类里使用@property声明属性后,又实现了setter和getter方法,那么在这个类以外可以正常通过点语法给该属性赋值和取值。就是说,在分类里使用@property声明属性,又实现了setter和getter方法后,可以认为给这个类添加上了属性。

本文转载自:

共有 人打赏支持
hanbing94
粉丝 2
博文 66
码字总数 38602
作品 0
朝阳
iOS查看屏幕帧数工具--YYFPSLabel

学习 YYKit 代码时,发现 ibireme 在项目里加入的一个查看当前屏幕帧数的小工具,效果如下: 挺实用,实现方法也很简单,但是思路特别棒。 这里是Demo: YYFPSLabel 这里我把这个小工具从 中...

yehot
2016/04/05
0
0
IOS App开启iTunes文件共享

关于IOS文件目录的一点记录 IOS的文件系统面向的是设备上的每个运行的应用程序。为了保证IOS系统的可用性和简单性,IOS设备的终端用户是无法直接访问文件系统的,同时设备上的app与用户一样也...

big军
2013/03/08
0
0
IOS学习,最简单的表格应用程序,学习,列出博客

IOS编程浅蓝教程,这是博客地址http://www.cnblogs.com/haichao/category/425378.html IOS编程浅蓝教程:锲子 IOS编程浅蓝教程(一)先决条件:开始iOS编程的必要准备 IOS编程浅蓝教程(二) Hel...

andy521zhu
2015/01/17
0
0
说说 NSTimer 的新 API

本文是我首发在iOS知识小集团队的,欢迎关注微博话题#ios知识小集#。 在以往的 iOS 版本中,我们为了避免 NSTimer 的循环引用问题,一个比较常用的解决办法是为 NSTimer 添加一个 category,...

halohily
05/03
0
0
定制iOS 7中的导航栏和状态栏

由于种种原因,申请了一个开源中国的帐号,也许会由于我的不耐心,不会亲自去一步步的写博文,但准备把自己看到的好的,都转载过来,就当时资源的存储,也算是一种推广吧。 iOS 7 教程:定制...

谁家的阿毛
2013/11/21
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何在Java中生成比特币钱包地址

让我们通过学习比特币(Bitcoin)如何实施该技术的各个方面来工作,好吗?该技术包括以下几个方面: 比特币地址bitcoin address是用来发送和接收比特币的。 交易transaction是比特币从一个地...

geek12345
6分钟前
0
0
面试必备Linux基础知识

学习Linux之前,我们先来简单的认识一下操作系统。 一 从认识操作系统开始 1.1 操作系统简介 我通过以下四点介绍什么操作系统: 操作系统(Operation System,简称OS)是管理计算机硬件与软件...

小小明童鞋
7分钟前
0
0
SpringBoot基础教程3-1-3 Quartz定时任务单点持久化

1 概述 实际项目中,复杂的定时任务都会结合持久化,动态改变定时任务状态,本文将介绍基于Quartz的定时任务单点持久化方式,通过RESTful风格,演示定时任务的CRUD,最后使用Swagger测试。 ...

Mkeeper
23分钟前
3
0
Android入门—文件目录解析

AndroidManifest.xml 是每个android程序中必须的文件,它位于整个项目的根目录。我们每天都在使用这个文件,往里面配置程序运行所必要的组件,权限,以及一些相关信息。但是对于这个文件,我...

haoyuehong
26分钟前
0
0
IDEA中Maven打包时如何跳过测试

方法1:直接使用IDEA提供的方式 Maven命令栏的工具栏有下图中的图标,上面就写着 Skip Tests 按下图标后,如下图,test就不可用了 直接使用package命令即可。 方法2:自己编辑maven命令 进入...

karma123
40分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部