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 NSCopyingdocs 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 Vendorclass has an array of objects called Car.
的Vendor类有称为对象的数组Car。
My Carobject:
我的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, Vendorholds an array of Carobjects. Carholds 2 arrays of other custom objects.
所以,Vendor持有一个Car对象数组。Car保存 2 个其他自定义对象的数组。
Both Vendorand Carare 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 Vendorobjects. I believe I need to implement the NSCopyingprotocol on Vendor, which may mean I need to implement it also on Carsince Vendorholds an array of Cars. That means I also need to implement it on the classes that are held in the 2 arrays belonging to the Carobject.
我需要复制一个Vendor对象数组。我相信我需要在 上实现NSCopying协议Vendor,这可能意味着我也需要在 上实现它,Car因为sVendor的数组Car。这意味着我还需要在属于该Car对象的 2 个数组中保存的类上实现它。
I'd really appreciate it if I could get some guidance on implementing NSCopyingprotocol 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 .mfile):
然后,在您的对象的实现(您的.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 NSObjectthat supports copying, you can call [thatObject copyWithZone:zone]for the new object. For primitive types (int, char, BOOLand 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 NSZonemight work for most cases, it is still incorrect.
此答案类似于已接受的答案,但使用allocWithZone:并针对 ARC 进行了更新。NSZone 是分配内存的基础类。虽然忽略NSZone可能适用于大多数情况,但它仍然是不正确的。
To correctly implement NSCopyingyou 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 NSCopyingprotocol:
在标头的接口声明中,指定您的类实现NSCopying协议:
@interface Car : NSObject<NSCopying>
{
...
}
In the .m implementation add a -(id)copyWithZonemethod 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 classtypes.
我没有使用copy()值类型,因为它们是“自动”复制的。但是,我不得不使用copy()的class类型。
I ignored the NSZoneparameter 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
}
}

