ios 实现 NSCopying
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4089238/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Implementing NSCopying
提问by Jeff Kelley
I've read the NSCopying
docs but I am still very unsure about how to implement what is required.
我已经阅读了NSCopying
文档,但我仍然非常不确定如何实现所需的内容。
My class Vendor
:
我的班级Vendor
:
@interface Vendor : NSObject
{
NSString *vendorID;
NSMutableArray *availableCars;
BOOL atAirport;
}
@property (nonatomic, copy) NSString *vendorID;
@property (nonatomic, retain) NSMutableArray *availableCars;
@property (nonatomic, assign) BOOL atAirport;
- (id)initFromVehVendorAvailsDictionary:(NSDictionary *)vehVendorAvails;
@end
The Vendor
class has an array of objects called Car
.
的Vendor
类有称为对象的数组Car
。
My Car
object:
我的Car
对象:
@interface Car : NSObject
{
BOOL isAvailable;
NSString *transmissionType;
NSMutableArray *vehicleCharges;
NSMutableArray *fees;
}
@property (nonatomic, assign) BOOL isAvailable;
@property (nonatomic, copy) NSString *transmissionType;
@property (nonatomic, retain) NSMutableArray *vehicleCharges;
@property (nonatomic, retain) NSMutableArray *fees;
- (id) initFromVehicleDictionary:(NSDictionary *)vehicleDictionary;
@end
So, Vendor
holds an array of Car
objects. Car
holds 2 arrays of other custom objects.
所以,Vendor
持有一个Car
对象数组。Car
保存 2 个其他自定义对象的数组。
Both Vendor
and Car
are init from a dictionary. I'll add one of these methods, they may or may not be relevant.
双方Vendor
并Car
从字典初始化。我将添加其中一种方法,它们可能相关,也可能不相关。
-(id)initFromVehVendorAvailsDictionary:(NSDictionary *)vehVendorAvails {
self.vendorCode = [[vehVendorAvails objectForKey:@"Vendor"]
objectForKey:@"@Code"];
self.vendorName = [[vehVendorAvails objectForKey:@"Vendor"]
objectForKey:@"@CompanyShortName"];
self.vendorDivision = [[vehVendorAvails objectForKey:@"Vendor"]
objectForKey:@"@Division"];
self.locationCode = [[[vehVendorAvails objectForKey:@"Info"]
objectForKey:@"LocationDetails"]
objectForKey:@"@Code"];
self.atAirport = [[[[vehVendorAvails objectForKey:@"Info"]
objectForKey:@"LocationDetails"]
objectForKey:@"@AtAirport"] boolValue];
self.venLocationName = [[[vehVendorAvails objectForKey:@"Info"]
objectForKey:@"LocationDetails"]
objectForKey:@"@Name"];
self.venAddress = [[[[vehVendorAvails objectForKey:@"Info"]
objectForKey:@"LocationDetails"]
objectForKey:@"Address"]
objectForKey:@"AddressLine"];
self.venCountryCode = [[[[[vehVendorAvails objectForKey:@"Info"]
objectForKey:@"LocationDetails"]
objectForKey:@"Address"]
objectForKey:@"CountryName"]
objectForKey:@"@Code"];
self.venPhone = [[[[vehVendorAvails objectForKey:@"Info"]
objectForKey:@"LocationDetails"]
objectForKey:@"Telephone"]
objectForKey:@"@PhoneNumber"];
availableCars = [[NSMutableArray alloc] init];
NSMutableArray *cars = (NSMutableArray *)[vehVendorAvails objectForKey:@"VehAvails"];
for (int i = 0; i < [cars count]; i++) {
Car *car = [[Car alloc] initFromVehicleDictionary:[cars objectAtIndex:i]];
[availableCars addObject:car];
[car release];
}
self.venLogo = [[[vehVendorAvails objectForKey:@"Info"]
objectForKey:@"TPA_Extensions"]
objectForKey:@"VendorPictureURL"];
return self;
}
So to summarize the scary problem.
所以总结一下可怕的问题。
I need to copy an array of Vendor
objects. I believe I need to implement the NSCopying
protocol on Vendor
, which may mean I need to implement it also on Car
since Vendor
holds an array of Car
s. That means I also need to implement it on the classes that are held in the 2 arrays belonging to the Car
object.
我需要复制一个Vendor
对象数组。我相信我需要在 上实现NSCopying
协议Vendor
,这可能意味着我也需要在 上实现它,Car
因为sVendor
的数组Car
。这意味着我还需要在属于该Car
对象的 2 个数组中保存的类上实现它。
I'd really appreciate it if I could get some guidance on implementing NSCopying
protocol on Vendor
, I can't find any tutorials on this anywhere.
如果我能得到一些关于在 上实现NSCopying
协议的指导,我真的很感激Vendor
,我在任何地方都找不到任何关于这方面的教程。
回答by Jeff Kelley
To implement NSCopying, your object must respond to the -copyWithZone:
selector. Here's how you declare that you conform to it:
要实现NSCopying,您的对象必须响应-copyWithZone:
选择器。以下是您声明您遵守它的方式:
@interface MyObject : NSObject <NSCopying> {
Then, in your object's implementation (your .m
file):
然后,在您的对象的实现(您的.m
文件)中:
- (id)copyWithZone:(NSZone *)zone
{
// Copying code here.
}
What should your code do? First, create a new instance of the object—you can call [[[self class] alloc] init]
to get an initialized obejct of the current class, which works well for subclassing. Then, for any instance variables that are a subclass of NSObject
that supports copying, you can call [thatObject copyWithZone:zone]
for the new object. For primitive types (int
, char
, BOOL
and friends) just set the variables to be equal. So, for your obejct Vendor, it'd look like this:
你的代码应该做什么?首先,创建对象的新实例——您可以调用[[[self class] alloc] init]
以获取当前类的初始化对象,这对于子类化非常有效。然后,对于作为NSObject
支持复制的子类的任何实例变量,您可以调用[thatObject copyWithZone:zone]
新对象。对于原始类型(int
,char
,BOOL
和朋友)刚刚成立的变量是相等的。因此,对于您的目标供应商,它看起来像这样:
- (id)copyWithZone:(NSZone *)zone
{
id copy = [[[self class] alloc] init];
if (copy) {
// Copy NSObject subclasses
[copy setVendorID:[[self.vendorID copyWithZone:zone] autorelease]];
[copy setAvailableCars:[[self.availableCars copyWithZone:zone] autorelease]];
// Set primitives
[copy setAtAirport:self.atAirport];
}
return copy;
}
回答by Justin Meiners
This answer is similar to the accepted, but uses allocWithZone:
and is updated for ARC. NSZone is foundation class for allocating memory. While ignoring NSZone
might work for most cases, it is still incorrect.
此答案类似于已接受的答案,但使用allocWithZone:
并针对 ARC 进行了更新。NSZone 是分配内存的基础类。虽然忽略NSZone
可能适用于大多数情况,但它仍然是不正确的。
To correctly implement NSCopying
you must implement a protocol method which allocates a new copy of the object, with properties that match the values of the original.
要正确实现,NSCopying
您必须实现一个协议方法,该方法分配对象的新副本,其属性与原始值匹配。
In the interface declaration in the header, specify that your class implements the NSCopying
protocol:
在标头的接口声明中,指定您的类实现NSCopying
协议:
@interface Car : NSObject<NSCopying>
{
...
}
In the .m implementation add a -(id)copyWithZone
method which looks something like the following:
在 .m 实现中添加一个如下所示的-(id)copyWithZone
方法:
- (id)copyWithZone:(NSZone*)zone
{
Car* carCopy = [[[self class] allocWithZone:zone] init];
if (carCopy)
{
carCopy.isAvailable = _isAvailable;
carCopy.transmissionType = _transmissionType;
... // assign all other properties.
}
return carCopy;
}
回答by kgaidis
Swift Version
迅捷版
Just call object.copy()
to create the copy.
只需调用object.copy()
即可创建副本。
I didn't use copy()
for value types since those are copied "automatically." But I had to use copy()
for class
types.
我没有使用copy()
值类型,因为它们是“自动”复制的。但是,我不得不使用copy()
的class
类型。
I ignored the NSZone
parameter because docssay it is deprecated:
我忽略了该NSZone
参数,因为文档说它已被弃用:
This parameter is ignored. Memory zones are no longer used by Objective-C.
该参数被忽略。Objective-C 不再使用内存区域。
Also, please note that this is a simplified implementation. If you have subclassesit gets a bit tricker and you should use dynamic type: type(of: self).init(transmissionType: transmissionType)
.
另外,请注意这是一个简化的实现。如果您有子类,它会变得有点棘手,您应该使用动态类型:type(of: self).init(transmissionType: transmissionType)
。
class Vendor {
let vendorId: String
var availableCars: [Car] = []
init(vendorId: String) {
self.vendorId = vendorId
}
}
extension Vendor: NSCopying {
func copy(with zone: NSZone? = nil) -> Any {
let copy = Vendor(vendorId: vendorId)
if let availableCarsCopy = availableCars.map({##代码##.copy()}) as? [Car] {
copy.availableCars = availableCarsCopy
}
return copy
}
}
class Car {
let transmissionType: String
var isAvailable: Bool = false
var fees: [Double] = []
init(transmissionType: String) {
self.transmissionType = transmissionType
}
}
extension Car: NSCopying {
func copy(with zone: NSZone? = nil) -> Any {
let copy = Car(transmissionType: transmissionType)
copy.isAvailable = isAvailable
copy.fees = fees
return copy
}
}