JKVValue 1.3.3

JKVValue 1.3.3

测试测试
语言语言 Obj-CObjective-C
许可证 MIT
发布上次发布2017年6月

Jeff Hui维护。



JKVValue 1.3.3

  • Jeff Hui

Objective-C的简单值对象。

值对象非常适合设计良好的程序!

它们非常适合用于记录来自API或内部应用程序数据的文档,但维护起来却很糟糕。

当你添加(或更改)属性时,你通常必须做

  • 添加@property
  • (可选)将它添加到构造函数中
  • 如果它支持NSMutableCopying,则将其添加到-[mutableCopyWithZone:]
  • 如果它支持NSCopying,则将其添加到-[copyWithZone:]
  • 要支持该属性的比较,请将其添加到-[isEqual:]
  • 要支持散列,请将其添加到-[hash]
  • 要支持反序列化,请将其添加到-[initWithCoder:]
  • 要支持序列化(NSSecureCoding),请将其添加到-[encodeWithCoder:]
  • 为了有吸引力的日志输出,请将其添加到-[description]
  • 为了在调试器中有吸引力的对象打印,请将其添加到-[debugDescription]

关于在代码中正确处理且具有可变和不可变版本的值对象,如Apple的Foundation数据结构,之前这一切都值得注意...但直到现在!

JKVValue可以将您的工作简化到仅设置@property和构造函数!

安装

子模块

如果您喜欢git submodules,请添加此项目并将其添加到您的项目中

git submodule add https://github.com/jeffh/JKVValue <Externals/JKVValue>
# checking out the stable version
cd <Externals/JKVValue>
git co tag v1.3.2

然后添加JKVValue静态库和公共头文件以供依赖项使用。

使用

您可以创建两个子类:JKVValue和JKVMutableValue。您声明的任何属性都将自动检测,并在NSCopying、NSMutableCopying、NSCoding、NSObject协议中自动支持相应的相应方法

#import "JKVValue.h"

@interface MyPerson : JKVValue
@property (strong, nonatomic, readonly) NSString *firstName;
@property (strong, nonatomic, readonly) NSString *lastName;

- (id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName;
@end

@interface MyPerson ()
@property (strong, nonatomic, readwrite) NSString *firstName;
@property (strong, nonatomic, readwrite) NSString *lastName;
@end

@implementation MyPerson

- (id)initWithFirstName:(NSString *)firstName lastName:(NSString *)lastName
{
    if (self = [super init]) {
        self.firstName = firstName;
        self.lastName = lastName;
    }
    return self;
}

@end

这样就结束了!现在所有的酷方法都支持了

MyPerson *person = [[MyPerson alloc] initWithFirstName:@"John" lastName:"Doe"];

// Copy returns same instance here, since it assumes immutability.
MyPerson *cloned = [person copy];

// this creates a new MyPerson instance, but still read only. We'll see how to change that later.
MyPerson *mutableClone = [person mutableCopy];

[person isEqual:mutableClone]; // => true
[NSSet setWithArray:@[person, mutableClone]]; // => set of 1 person

// get a nice description for free
[person description]; // => <MyPerson 0xdeadbeef firstName=John lastName=Doe>
// even in LLDB:
// > po person => <MyPerson 0xdeadbeef firstName=John lastName=Doe>

如果想要-[mutableCopy]用不同的、实际的、可变的类实现,没问题!

@class MyMutablePerson;

@implementation MyPerson

- (Class)JKV_mutableClass
{
    return [MyMutablePerson class];
}

@end

@interface MyMutablePerson : MyPerson
@property (strong, nonatomic, readwrite) NSString *firstName;
@property (strong, nonatomic, readwrite) NSString *lastName;
@end

@implementation MyMutablePerson

@synthesize firstName;
@synthesize lastName;

- (BOOL)JKV_isMutable
{
    return YES; // to hint to JKVValue that this concrete class is mutable.
}

- (Class)JKV_immutableClass
{
    return [MyPerson class]; // tells JKVValue which class to create for the immutable variant
}

@end

现在您可以在可变和不可变变体之间切换,类似于NSArray或NSDictionary

// assuming MyPerson *person from above
MyMutablePerson *mutablePerson = [person mutableCopy];
MyPerson *immutablePerson = [mutablePerson copy];

如果您更喜欢只使用可变对象,只需使用JKVMutableValue即可,它可以方便地覆盖JKVValue的-[JVK_isMutable]以使其为YES而不是默认的NO

要注意的是,如果它们分别支持NSCopying或NSMutableCopying,则会在所有属性上调用copy/mutableCopy。

基本差异

你有大量两个字段的对象,想知道为什么 -[isEqual:] 失败?请使用 -[differenceToObject:]

MyPerson *person1 = [MyPerson new];
person1.firstName = @"John";
MyPerson *person2 = [MyPerson new];
person2.firstName = @"James";
[person1 differenceToObject:person2]; // => @{@"firstName": @[@"John", @"James"};
[person1 differenceToObject:@1]; // => @{@"class": @[[MyPerson class], NSClassFromString(@"__CFNSNumber")}

测试

此库包含一个工厂类 JKVFactory,可以轻松生成预构建的对象。它与 JKVValueJKVMutableValue 并没有直接关联,但用于简化生成预填充对象的开销。

对于最简单的情况,即属性值不为零的值对象

JKVFactory *personFactory = [JKVFactory factoryForClass:[MyPerson class]]
MyPerson *person = [personFactory object];

如果您想要更多定制,建议从 JKVFactory 继承并使用自定义的 -[init] 方法

@interface MyPersonFactory : JKVFactory
@end

@implementation MyPersonFactory

- (id)init
{
    return [super initWithClass:[MyPerson class] properties:@{@"firstName": @"John"}];
}

@end

// shortcut to [[MyPersonFactory new] object]
MyPerson *person = [MyPersonFactory buildObject];

需要特殊属性的对象吗?

[MyPersonFactory buildObjectWithProperties:@{@"firstName": @"James"}];

需要将属性设为 nil 吗?请使用 [NSNull null]

[MyPersonFactory buildObjectWithProperties:@{@"lastName": [NSNull null]}];

Objective-C 容器的描述

JKVValue 为 NSArraysNSDictionariesNSSets 属性提供了好的描述。默认情况下,它不会覆盖这些类中的默认实现。您可以告诉 JKVValue 覆盖它们

[JKVObjectPrinter swizzleContainers];
// you can undo the swizzling using [JKVObjectPrinter unswizzleContainers].

问题注意点

由于实现细节可能导致的一些意外情况

  • 未由实例变量支持的属性将被忽略。
  • 属性赋值使用 KVC 进行,允许即使标记为只读属性也能进行属性修改。JKVValue 使用一个私有的 -[init] 构造函数来创建初始对象。
  • 弱属性不会用于相等(或哈希)比较,因为它们的生命周期在任意时刻都可能被一个值对象消耗。
  • 弱属性通过复制来赋值,并且不会复制(复制的弱引用将会立即被释放)。
  • 弱属性被正确地编码、解码为条件对象。
  • 由于 Objective-C 运行时,弱只读属性对 JKVValues 来说表现得像强属性。
  • 如果您使用不可变-可变模式,则不能让您的构造函数直接使用 ivars,因为这些可变版本将会用它们自己的内容覆盖它们。