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
,可以轻松生成预构建的对象。它与 JKVValue
或 JKVMutableValue
并没有直接关联,但用于简化生成预填充对象的开销。
对于最简单的情况,即属性值不为零的值对象
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]}];
JKVValue 为 NSArrays
、NSDictionaries
和 NSSets
属性提供了好的描述。默认情况下,它不会覆盖这些类中的默认实现。您可以告诉 JKVValue 覆盖它们
[JKVObjectPrinter swizzleContainers];
// you can undo the swizzling using [JKVObjectPrinter unswizzleContainers].
由于实现细节可能导致的一些意外情况
-[init]
构造函数来创建初始对象。