2009-09-22 11 views
104

Potrzebuję głęboko skopiować obiekt niestandardowy, który ma własne obiekty. Czytałem dookoła i jestem nieco zdezorientowany, jak odziedziczyć NSCopying i jak używać NSCopyObject. Czy ktoś może mi pomóc? Dziękuje za przeczytanie!Jak skopiować obiekt w celu c

+1

Świetne [TUTORIAL] (http://www.techotopia.com/index.php/Copying_Objects_in_Objective-C) do zrozumienia kopii, mutableCopy i copyWithZone – horkavlna

Odpowiedz

182

Jak zwykle w przypadku typów odniesienia, istnieją dwie pojęcia "kopia". Jestem pewien, że je znasz, ale dla kompletności.

  1. Kopiowanie bitowe. W tym celu wystarczy skopiować bit pamięci na bit - tak robi NSCopyObject. Prawie zawsze nie jest to, czego chcesz. Obiekty mają wewnętrzny stan, inne obiekty itp. I często przyjmują założenia, że ​​są jedynymi, które posiadają odniesienia do tych danych. Kopie bitowe łamią to założenie.
  2. Głęboka, logiczna kopia. W tym celu tworzymy kopię obiektu, ale nie robiąc tego krok po kroku - chcemy obiektu, który zachowuje się tak samo dla wszystkich intencji i celów, ale nie jest (koniecznie) identycznym z pamięcią klonem oryginału - Ręczny C nazywa ten obiekt "funkcjonalnie niezależnym" od jego oryginału. Ponieważ mechanizmy tworzenia "inteligentnych" kopii różnią się w zależności od klasy, prosimy o ich wykonanie. To jest protokół NSCopying.

Chcesz tego drugiego. Jeśli jest to jeden z twoich obiektów, musisz po prostu przyjąć protokół NSCopying i implementować - (id) strefa copyWithZone: (NSZone *). Możesz robić, co chcesz; choć pomysł polega na tym, że robisz prawdziwą kopię siebie i zwracasz ją. Nazywasz copyWithZone we wszystkich swoich polach, aby wykonać głęboką kopię. Prostym przykładem jest

@interface YourClass : NSObject <NSCopying> 
{ 
    SomeOtherObject *obj; 
} 

// In the implementation 
-(id)copyWithZone:(NSZone *)zone 
{ 
    // We'll ignore the zone for now 
    YourClass *another = [[YourClass alloc] init]; 
    another.obj = [obj copyWithZone: zone]; 

    return another; 
} 
+0

Ale robisz odbiorcę skopiowanego obiektu odpowiedzialnego za jego uwolnienie! Nie powinieneś 'autoreasować' tego, czy też coś tu brakuje? – bobobobo

+29

@bobobobo: Nie, podstawowa zasada pamięci Objective-C management to: Przejmujesz własność obiektu, jeśli utworzysz go za pomocą metody, której nazwa zaczyna się od "alloc" lub "new" lub zawiera "copy". "copyWithZone:" spełnia te kryteria, dlatego musi zwrócić obiekt z zachowaniem liczba +1. –

+1

@Adam Czy istnieje powód, aby używać 'alloc' zamiast' allocWithZone: ', ponieważ strefa została przekazana i n? – Richard

22

dokumentacji Apple mówi

A subclass version of the copyWithZone: method should send the message to super first, to incorporate its implementation, unless the subclass descends directly from NSObject.

dodać do istniejącego odpowiedź

@interface YourClass : NSObject <NSCopying> 
{ 
    SomeOtherObject *obj; 
} 

// In the implementation 
-(id)copyWithZone:(NSZone *)zone 
{ 
    YourClass *another = [super copyWithZone:zone]; 
    another.obj = [obj copyWithZone: zone]; 

    return another; 
} 
+1

Ponieważ YourClass pochodzi bezpośrednio z NSObject, nie sądzę, że jest to konieczne. – Mike

+2

Dobrze, ale jest to ogólna zasada, na wypadek, gdyby była to długa hierarchia klasowa. –

+8

Wystąpił błąd: 'Brak widocznego interfejsu @ dla" NSObject "deklaruje selektor 'copyWithZone:''. Domyślam się, że jest to wymagane tylko wtedy, gdy dziedziczymy z innej niestandardowej klasy, która zaimplementuje autorelease 'copyWithZone' – Sam

2
another.obj = [obj copyWithZone: zone]; 

myślę, że ta linia powoduje wyciek pamięci, bo dostęp do obj poprzez właściwość, która jest (zakładam) zadeklarowana jako retain. Tak więc, zostanie zatrzymany zliczenie zostanie zwiększone o wartość i copyWithZone.

wierzę, powinno być:

another.obj = [[obj copyWithZone: zone] autorelease]; 

czyli

SomeOtherObject *temp = [obj copyWithZone: zone]; 
another.obj = temp; 
[temp release]; 
+0

Nie, metody alloc, copy, mutableCopy, new powinny zwracać obiekty nieautorealizowane. – kovpas

+0

@kovpas, jesteś pewien, że mnie rozumiesz, prawda? Nie mówię o zwróconym obiekcie, mówię o jego polach danych. –

+0

tak, moje złe, przepraszam. czy mógłbyś jakoś edytować swoją odpowiedź, abym mógł usunąć minus? :)) – kovpas

19

nie wiem diference między tym kodem i kopalni, ale mam problemy z tego rozwiązania, więc czytam trochę więcej i okazało się, że musimy ustawić obiekt przed zwróceniem go. Mam na myśli coś takiego

#import <Foundation/Foundation.h> 

@interface YourObject : NSObject <NSCopying> 

@property (strong, nonatomic) NSString *nombre;//nombre del medicamento 
@property (strong, nonatomic) NSString *linea;//linea a la que pertenece 
@property (strong, nonatomic) NSMutableString *tags;//palabras por las que se puede encontrar en el buscador 
@property (strong, nonatomic) NSString *htmlSource;//código html para mostrar su contenido 
@property (strong, nonatomic) NSMutableString *obj; 

-(id) copyWithZone: (NSZone *) zone; 

@end 


@implementation YourObject 


-(id) copyWithZone: (NSZone *) zone 
{ 
    YourObject *copy = [[YourObject allocWithZone: zone] init]; 

    [copy setNombre: self.nombre]; 
    [copy setLinea: self.linea]; 
    [copy setTags: self.tags]; 
    [copy setHtmlSource: self.htmlSource]; 

    return copy; 
} 

kładę tę odpowiedź za przyczynę, mam wiele problemów z tym problemem, a ja nie mam pojęcia o tym, dlaczego!, nie wiem różnicę, ale to działa i może może być przydatny:)

0

Istnieje również użycie operatora -> do kopiowania. Na przykład:

-(id)copyWithZone:(NSZone*)zone 
{ 
    MYClass* copy = [MYClass new]; 
    copy->_property1 = self->_property1; 
    ... 
    copy->_propertyN = self->_propertyN; 
    return copy; 
} 

Powód jest taki, że wynikowy skopiowany obiekt powinien odzwierciedlać stan oryginalnego obiektu. "."operator może wprowadzić efekty uboczne, ponieważ ten nazywa wywołujące, które z kolei mogą zawierać logikę."