2012-04-17 36 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