美文网首页
第26条:勿在分类中声明属性

第26条:勿在分类中声明属性

作者: MrSYLong | 来源:发表于2018-09-23 23:15 被阅读5次

属性是封装数据的方式。从技术上说,分类里也可以声明属性,但这个做法应该尽量避免,原因在于,除了“class-continuation分类”之外,其他分类都无法向类中新增实例变量,因此它们无法把实现属性所需的实例变量合成出来。

// 分类头文件添加属性,编译器会有警告信息 原因:分类无法合成与 friendsArray属性相关的实例变量
#import "EOCPerson.h"

@interface EOCPerson (FriendsShip)

@property (nonatomic, strong) NSArray *friendsArray;

@end

解决方法一:
@dynamic声明属性,在分类中为属性实现存取方法,

// 头文件
#import "EOCPerson.h"

@interface EOCPerson (FriendsShip)

@property (nonatomic, strong) NSArray *friendsArray;

- (void)setFriendsArray:(NSArray *)friendsArray;

- (NSArray *)friendsArray;

@end

// 实现文件
#import "EOCPerson+FriendsShip.h"

@implementation EOCPerson (FriendsShip)

@dynamic friendsArray;

- (void)setFriendsArray:(NSArray *)friendsArray
{
    // 这里也不能给属性赋值,需要另外一个变量,接这个friendsArray
    self.friendsArray = friendsArray;
}

- (NSArray *)friendsArray
{
    return self.friendsArray;
}

@end

解决方法二:
使用消息转发机制,在运行期拦截方法,并提供其实现。

解决方法三:
关联对象能够解决在分类中不能合成实例变量的问题。

#import <objc/runtime.h>
#import "EOCPerson+FriendsShip.h"

static const char *kFriendsPropertyKey = "kFriendsShipPropertyKey";

@implementation EOCPerson (FriendsShip)

@dynamic friendsArray;

- (void)setFriendsArray:(NSArray *)friendsArray
{
    objc_setAssociatedObject(self, kFriendsPropertyKey, friendsArray, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (NSArray *)friendsArray
{
    return objc_getAssociatedObject(self, kFriendsPropertyKey);
}

@end

关联对象可行,但不太理想,相似代码写多遍,而且内存管理问题容易出错,属性的内存管理语义与设置管理对象时所用的内存管理语义一致才可以。

属性应该定义在“主接口”中,不要定义在分类中。分类机制目标是扩展类的功能,而非封装数据。

有时候只读属性可以在分类中使用。

// 头文件
#import <Foundation/Foundation.h>

@interface NSCalendar (EOC_Additions)

- (NSArray *)eoc_allMonths;

@end

// 实现文件
#import "NSCalendar+EOC_Additions.h"

@interface NSCalendar(EOC_Additions)

@property (nonatomic, strong, readonly) NSArray *eoc_allMonths;

@end

@implementation NSCalendar (EOC_Additions)

- (NSArray *)eoc_allMonths
{
    if ([self.calendarIdentifier isEqualToString:NSGregorianCalendar]) {
        return @[@"Jan",@"Feb",@"Mar",@"Apr",@"May",@"June",@"jul",@"Aug",@"Sep",@"Oct",@"Nov",@"Dec"];
    } else if (/* 其他情况 */) {
        // 返回其他结果
    }
}

@end

获取方法并不访问数据,而且属性也不需要由实例变量来实现,属性所需的获取方法已经实现,不会再为属性自动合成实例变量,编译器不会发出警告。

相关文章

  • 《Effective Objective-C 2.0 》 阅读笔

    第26条:勿在分类中声明属性 要点 把封装数据所用的全部属性都定义在主接口里。 在“Class-continuat...

  • 第26条:勿在分类中声明属性

    属性是封装数据的方式。从技术上说,分类里也可以声明属性,但这个做法应该尽量避免,原因在于,除了“class-con...

  • 看书笔记26-30

    二十六:勿在分类中声明属性 把封装数据所用的全部属性都定义在主接口里。在"class-continuation分类...

  • 勿在分类中声明属性--Effective笔记

    属性是封装数据的方式。虽然分类也可以声明属性,但这种做法还是要尽量避免。因为分类中一般是无法新增实例变量(可用关联...

  • 分类中声明属性

    分类(category).h中: .m中: 这种分类如果声明属性, 编译器会报警告。意思是此分类无法生成属性相关实...

  • ios 分类中如何添加数据成员

    分类中可以声明属性,因为声明属性其实就是声明设置方法和获取方法。但是分类中不可以合成属性,因为合成属性其实就是创建...

  • iOS 中协议中可以定义属性及定义属性的方式方法

    iOS中协议中和分类中是可以用@property形式声明属性的,只不过在协议、分类中声明的属性,只有对应的sett...

  • 333,iOS 中protocol中可以定义@property及

    iOS中协议中和分类中是可以用@property形式声明属性的,只不过在协议、分类中声明的属性,只有对应的sett...

  • 52个有效方法(26) - 勿在分类中声明属性

    分类机制,应将其理解为一种手段,目标在于扩展类的功能,而非封装数据。 分类是用于给原有类添加方法的,因为分类的结构...

  • 关联属性

    分类中不可以添加成员变量 分类中可以声明属性,分类中声明属性只会生成方法的声明,但不会生成成员变量和方法的实现。 ...

网友评论

      本文标题:第26条:勿在分类中声明属性

      本文链接:https://www.haomeiwen.com/subject/ltyznftx.html