2012-04-17 52 views
2

我有一个对象imageView1。我想创建另一个对象来保留imageView1的深层副本。 这样,如何在UIKit中为类实现深层副本?

UIImageView *imageView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background.png"]]; 
UIImageView *imageView2 = [imageView1 copy]; 

我知道但这并没有工作,因为的UIImageView不符合NSCopying。但我应该怎么做 ?

+0

在任何体系结构中复制UI组件并不是一个好主意。 – Sulthan 2012-04-17 10:55:10

+0

@Sulthan我明白你的意思。但是,我真的需要UIImageView来保存一些关于模型的数据。当然,它可以存储CGRect,fileName等。我认为这比直接使用UIImageView要复杂。感谢您的经验。我会照顾这个。 – tzzzoz 2012-04-17 11:55:58

+0

你应该能够从你的模型创建UI,而不是让你的模型成为UI的一部分。 – Sulthan 2012-04-17 12:29:23

回答

4

要创建UIImageView对象的深层副本,需要使用NSKeyedArchiver将其归档,然后使用NSKeyedUnarchiver将其解压缩,但由于UIImage不符合NSCoding协议,因此存在此方法的问题。你首先需要做的是扩展UIImage类来支持NSCoding。

与名NSCodingUIImage添加一个新的类别,并把下面的代码:

的UIImage + NSCoder.h

#import <UIKit/UIKit.h> 

@interface UIImage (NSCoding) 
- (id)initWithCoder:(NSCoder *)decoder; 
- (void)encodeWithCoder:(NSCoder *)encoder; 
@end 

的UIImage + NSCoder.m

#import "UIImage+NSCoder.h" 

@implementation UIImage (NSCoding) 
- (id)initWithCoder:(NSCoder *)decoder { 
    NSData *pngData = [decoder decodeObjectForKey:@"PNGRepresentation"]; 
    [self autorelease]; 
    self = [[UIImage alloc] initWithData:pngData]; 
    return self; 
} 
- (void)encodeWithCoder:(NSCoder *)encoder { 
    [encoder encodeObject:UIImagePNGRepresentation(self) forKey:@"PNGRepresentation"]; 
} 

@end 

然后添加一个名称为的新类别

的UIImageView + DeepCopy.h

#import <UIKit/UIKit.h> 

@interface UIImageView (DeepCopy) 
-(UIImageView *)deepCopy; 
@end 

的UIImageView + DeepCopy.m

#import "UIImageView+DeepCopy.h" 
#import "UIImage+NSCoder.h" 

@implementation UIImageView (DeepCopy) 

-(UIImageView *)deepCopy 
{ 
    NSMutableData *data = [[NSMutableData alloc] init]; 
    NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; 
    [archiver encodeObject:self forKey:@"imageViewDeepCopy"]; 
    [archiver finishEncoding]; 
    [archiver release]; 

    NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; 
    UIImageView *imgView = [unarchiver decodeObjectForKey:@"imageViewDeepCopy"]; 
    [unarchiver release]; 
    [data release]; 

    return imgView; 
} 

@end 

用法:上的UIImageView和下面的代码(为前。) 导入您的UIImageView + DeepCopy.h

UIImageView *imgView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"picture.jpg"]]; 
UIImageView *imageView2 = [imgView1 deepCopy]; 
+0

这非常聪明!但是,如果我在imageView1中有一些子图像视图。如何修改这个方法? – tzzzoz 2012-04-17 12:20:48

+0

这种方法将复制整个对象图,所以你不需要改变任何东西。 UIImageView * imgView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@“picture.jpg”]]; UIImageView * imgView2 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@“picture2.jpg”]]; [imgView1 addSubView:imgView2]; UIImageView * copiedResult = [imgView1 deepCopy]; – graver 2012-04-17 12:28:37

+0

好吧,我会试试看。谢谢! – tzzzoz 2012-04-17 12:34:53

4

浅拷贝
拷贝对象的一种方法是浅拷贝。在这个过程中,B被附加到与A相同的存储块。这被称为地址复制。 这会导致A和B之间共享相同数据的情况,因此修改其中一个会改变另一个。 B的原始内存块现在不再从任何地方引用。如果语言没有自动垃圾收集,则B的原始内存块可能已经泄漏。 浅拷贝的优点是它们的执行速度很快,并且不依赖于数据的大小。 不是由单片块组成的对象的按位拷贝是浅拷贝。

深拷贝
另一种方法是深拷贝。这里的数据实际上是复制过来的。结果与浅拷贝给出的结果不同。优点是A和B不依赖于对方,而是以较慢的更昂贵的副本为代价。

enter image description here
所以下面的代码片段将为你做深层复制。

UIImageView *imageView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"background.png"]]; 
UIImageView *imageView2 = [[UIImageView alloc] initWithImage:imageView1.image]; 
+0

我已经尝试过。但是,我发现imageView2.image是imageView1.image的参考。这两个图像都有相同的内存地址。此外,imageView1可能有一些子视图。 – tzzzoz 2012-04-17 12:13:27

+0

@tzzzoz,所以代码不会做深层复制,对吧? – gabbler 2014-10-06 06:23:02

+0

对于这些UIImage对象,我认为它不会做深层复制。 你可以试试看看这两个UIImage对象是否有相同的内存地址。 – tzzzoz 2014-10-08 11:05:59