Objective-C的简单值对象。
值对象非常适合设计良好的程序!
它们非常适合用于记录来自API或内部应用程序数据的文档,但维护起来却很糟糕。
当你添加(或更改)属性时,你通常必须做
@propertyNSMutableCopying,则将其添加到-[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] 构造函数来创建初始对象。