Mic*_*tum 4 objective-c immutability
我想在Objective-C中有一个带有不可变字段的Object.
在C#中,我将使用属性与私有setter和一个大的构造函数.
我会在Objective-C中使用什么?
使用@property似乎不允许我将setter声明为private.
运用
initWithData: (NSString*) something createDate: (NSDate*) date userID: (long) uid
Run Code Online (Sandbox Code Playgroud)
如果我要设置超过4个属性,似乎过于冗长.
我会在.h文件中声明getter,只在.m中声明setter吗?
我需要在某些东西和日期上使用保留或复制(顺便说一下:我应该使用这两个中的哪一个?),所以我需要在setter中使用一些代码.
或者甚至还有其他类似不可变关键字的东西?
Chr*_*son 12
您可以拥有一个公共只读属性,并使用私有读写属性为您的类中的属性提供一个setter,如果您确实需要它.但是,您应该考虑是否有必要.
作为示例,请考虑以下声明和不可变Person类的定义:
// Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject {
@private
NSString *name_;
NSDate *dateOfBirth_;
}
@property (readonly, copy) NSString *name;
@property (readonly, copy) NSDate *dateOfBirth;
/*! Initializes a Person with copies of the given name and date of birth. */
- (id)initWithName:(NSString *)name dateOfBirth:(NSDate *)dateOfBirth;
@end
// Person.m
#import "Person.h"
@implementation Person
@synthesize name = name_;
@synthesize dateOfBirth = dateOfBirth_;
- (id)initWithName:(NSString *)name dateOfBirth:(NSDate *)dateOfBirth {
self = [super init];
if (self) {
name_ = [name copy];
dateOfBirth_ = [dateOfBirth copy];
}
return self;
}
- (void)dealloc {
[name_ release];
[dateOfBirth_ release];
[super dealloc];
}
@end
Run Code Online (Sandbox Code Playgroud)
首先,请注意我没有声明一个类扩展Person.m,重新声明name和dateOfBirth属性为readwrite.这是因为该类的目的是不可变的; 如果实例变量只在初始化时设置,则不需要设置setter.
另请注意,我声明的实例变量的名称与属性不同.这清楚地表明了作为类的编程接口的属性与作为类的实现细节的实例变量之间的区别.我见过太多的开发人员(特别是那些刚接触Mac OS X和iOS的人,包括很多来自C#的人)将属性与可能用于实现它们的实例变量混淆.
需要注意的第三点是,copy即使它们是只读的,我也声明了这两个属性.有两个原因.第一个是虽然这个类的直接实例是不可变的,但没有什么能阻止创建一个MutablePerson子类.事实上,这甚至可能是可取的!因此,copy明确指出超类的期望是什么 - name和dateOfBirth属性本身的值不会改变.它也暗示了这一点-initWithName:dateOfBirth:也可能是副本; 它的文档评论应该清楚.其次,NSString和NSDate都是值类; 不可变的副本应该很便宜,而且你不想挂在可变子类的实例上,这个子类将从你自己的类下面改变.(现在实际上并没有NSDate的任何可变子类,但这并不意味着有人无法创建自己的......)
最后,不要担心您的指定初始化程序是否冗长.如果对象的实例无效,除非它处于某种特定状态,那么您指定的初始化程序需要将其置于该状态 - 并且需要采用适当的参数来执行此操作.
还有一两件事:如果你要创建一个不变的值类这样,你应该也可能实现自己-isEqual:和-hash快速比较方法,而且很可能符合NSCopying为好.例如:
@interface Person (ImmutableValueClass) <NSCopying>
@end
@implementation Person (ImmutableValueClass)
- (NSUInteger)hash {
return [name_ hash];
}
- (BOOL)isEqual:(id)other {
Person *otherPerson = other;
// Using [super isEqual:] to allow easier reparenting
// -[NSObject isEqual:] is documented as just doing pointer comparison
return ([super isEqual:otherPerson]
|| ([object isKindOfClass:[self class]]
&& [self.name isEqual:otherPerson.name]
&& [self.dateOfBirth isEqual:otherPerson.dateOfBirth]));
}
- (id)copyWithZone:(NSZone *)zone {
return [self retain];
}
@end
Run Code Online (Sandbox Code Playgroud)
我在自己的类别中声明了这一点,以便不重复我之前作为示例显示的所有代码,但在实际代码中,我可能会把所有这些都放在main @interface和@implementation.请注意,我没有重新声明-hash和-isEqual:,我只定义了他们,因为他们已经通过NSObject的声明.而且因为这是一个不可变的值类,我可以-copyWithZone:纯粹通过保留来实现self,我不需要制作对象的物理副本,因为它应该表现完全相同.
但是,如果您使用的是Core Data,请不要这样做; 核心数据为您实现对象唯一性,因此您不能拥有自己的-hash或-isEqual:实现.为了更好的衡量,你不应该真正符合Core Data NSManagedObject子类中的NSCopying; "复制"作为核心数据对象图的一部分的对象意味着需要仔细考虑,通常更多的是控制器级行为.
| 归档时间: |
|
| 查看次数: |
2440 次 |
| 最近记录: |