Frage

Ich arbeite an einer iPhone-Applikation. Ich habe ein Objekt der Klasse Row, die zahlreiche Objekte der Klasse Block lösen muss. Jeder Block verfügt derzeit über eine Eigenschaft, die eine Instanzvariable der Klasse Row behält.

@interface Block : UIImageView {
  Row *yCoord;
}
@property (nonatomic,retain) Row *yCoord;
@end

Jeder Row enthält eine NSMutableArray dieser Blöcke.

@interface Row : NSObject {
    NSMutableArray *blocks;
}
-(void)addBlock:(Block*)aBlock;
@end

@implementation Row
-(void)addBlock:(Block*)aBlock {
    [blocks addObject:aBlock];
    aBlock.yCoord = self;
}
@end

Ich verstehe, dass dies eine kreisförmige Referenz. Apples Dokumentation besagt, dass, um ein Objekt mit einer kreisförmigen Referenz ausplanen Ich brauche eine schwache Referenz statt eine starke Referenz (a behalten Eigenschaft), aber es durch nicht folgen und erklärt, wie genau gehe ich so tun. Ich plane, alle Blöcke innerhalb einer Zeile zu lösen und dealloc sowie die Reihe selbst gleichzeitig. Wie kann ich einen schwachen Verweis in jedem meiner Blocks ihrer „Eltern“ Row up?

War es hilfreich?

Lösung

Edit: Da die Fragesteller hat er nicht Garbage Collection geklärt ist mit (iPhone derzeit nicht unterstützt), mein Rat ist, Zyklen zu vermeiden, indem nur eine der Aufgaben, die andere behalten, wie Sie mit einem Delegierten tun würde. Wenn Eigenschaften, verwenden Sie „zuweisen“ statt „behalten“, dies zu erreichen. Zum Beispiel:

@property (nonatomic,assign) Row *yCoord;

Der Rest meiner Antwort Antwort bezieht sich auf "schwache Verweise" in Bezug auf die Objective-C 2.0 und GC.


Wenn Sie mit der Garbage Collection (10.5 +) arbeiten, wird ein schwacher Verweis wird durch das Vorsetzen eine Variablendeklaration mit erstellt __weak . Wenn Sie dieser Variablen zugewiesen, die GC (wenn aktiviert) hält der Referenzspur und wird es automatisch für Sie Null aus, wenn alle starken Verweise auf das referenzierte Objekt verschwinden. (Wenn GC nicht aktiviert ist, das __weak Attribut wird ignoriert.)

So können Sie sicher die obige Antwort ändern mit Garbage Collection spielen schöneren (aktuell 10.5 + und vielleicht einen Tag auf dem iPhone) wie folgt: (Siehe im Zusammenhang Apple-docs .)

@property (nonatomic,assign) __weak Row *yCoord;

Chris Hanson (wo Sie nähere Informationen finden):

  

„Durch eine Instanz Variablendeklaration mit __weak prefixing, der Garbage Collector sagen, dass, wenn es der einzige Verweis auf ein Objekt, dass das Objekt sollte sammelbaren in Betracht gezogen werden.“

Ich würde das klarstellen, indem er sagt: „Wenn es kein nicht-schwacher Verweis auf ein Objekt ist“. Sobald die letzte starke Referenz entfernt wird, kann das Objekt gesammelt werden, und alle schwachen Verweise automatisch auf Null gestellt werden.

Hinweis: Dies ist nicht direkt zur Schaffung schwache Verweise verwendet, aber es gibt auch ein __strong Attribut, aber da Objective-C Objektvariablen sind starke Referenzen standardmäßig es in der Regel nur für rohe C Zeiger auf Dinge wie structs oder Primitive, die nicht der Garbage Collector als Wurzeln behandeln verwendet wird, und wird unter Ihnen erhoben, wenn Sie sie so stark nicht erklären. (Während der Mangel an __weak verursachen kann Zyklen und Speicherlecks halten, der Mangel an __strong im Speicher Stampfen führen kann und wirklich seltsam und heimtückisch Fehler, die nicht-deterministisch auftreten und kann ziemlich schwierig sein, nach unten zu verfolgen.)

Andere Tipps

Einfach ändern zuweisen statt behalten, nicht mehr zirkuläre Referenzen.

@interface Block : UIImageView {
  Row *yCoord;
}
@property (nonatomic,assign) Row *yCoord;
@end

Ein schwacher Verweis ist einfach eine Zuordnung (es sei denn, Sie Garbage Collection reden, die eine ganze separate Dose Würmer, aber leide nicht an Zyklen beibehalten).

Normalerweise in Cocoa, Row würde die Block Objekte behalten (indem man sich in der NSMutableArray einschließlich), aber Block nicht Row behalten, jeder würde es einfach speichern, in einer Ivar (mit einer "zuweisen" Eigenschaft).

Solange Row vorsichtig ist, jede Block freizugeben, bevor es freigegeben wird (dh seine dealloc sollte die NSMutableArray freisetzen, die die Blöcke so lange freigeben wird, wie niemand sonst irgendwelche Hinweise darauf hat), dann wird alles verwenden je nach Zuordnung aufgehoben .

Sie können auch die Vorsichtsmaßnahmen ergreifen, der die Zeile Bezug von Blöcken Nullstellung, bevor Sie die entiries aus dem Array entfernt, so etwas wie:

- (void) dealloc {
    for (Block* b in _blocks) {
        b.row = nil;
    }
    [_blocks release];
    [super dealloc];
}

Dabei gilt _blocks die Ivar durch die Blöcke Eigenschaft verwiesen wird.

Verwendung zuweisen schwache Verweise zu schaffen, kann in einem Multi-Thread-System unsicher sein, insbesondere dann, wenn entweder Aufgabe kann durch ein drittes Objekt zurückgehalten werden, und dann dereferenziert das andere Objekt verwendet.

Glücklicherweise ist dies oft ein Problem der Hierarchie, und das Objekt die schwache Referenz enthält, kümmert sich nur um das Objekt bezieht er sich für die genannten Objekt Lebzeiten. Dies ist die übliche Situation mit einem Superior-<->. Unterordnungsverhältnis

Ich denke, dass der Fall in Kommentar der OP-Karten dazu mit Row = Überlegene, Block = Untergeordnete.

In diesem Fall würde ich einen Griff verwenden, um die Superior von der Untergebene zu verweisen:

// Superior.h

@class Superior;

@interface SuperiorHandle : NSObject {
    @private
        Superior* superior_;
}

// note the deliberate avoidance of "nonatomic"
@property (readonly) Superior *superior;

@end

@interface Superior : NSObject {
    @private
        SuperiorHandle *handle_;
        // add one or more references to Subordinate instances
}

// note the deliberate avoidance of "nonatomic"
@property (readonly) SuperiorHandle *handle;

@end


// Superior.m

#import "Superior.h"

@implementation SuperiorHandle

@synthesize
    superior = superior_;

- (id)initWithSuperior:(Superior *)superior {
    if ((self = [super init])) {
        superior_ = superior; // weak reference
    }
}

- (void)invalidate {
    @synchronized (self) {
        superior_ = nil;
    }
}

- (Superior *)superior {
    @synchronized (self) {
        // retain and autorelease is required to prevent dealloc before we're ready, thanks to AndroidDev for pointing out this mistake
        return [[superior_ retain] autorelease];
    }
}

@end

@implementation Superior

@synthesize
    handle = handle_;

- (id)init {
    if ((self = [super init])) {
        handle_ = [[SuperiorHandle alloc] initWithSuperior:self];
    }
    return self;
}

- (void)dealloc {
    [handle_ invalidate];
    [handle_ release];

    [super dealloc];
}

@end


// Subordinate.h

@class Superior;
@class SuperiorHandle;

@interface Subordinate : NSObject {
    @private
        SuperiorHandle *superior_handle_;
}

@property (readonly) Superior *superior;

@end


// Subordinate.m

#import "Subordinate.h"

#import "Superior.h"

@implementation Subordinate

// no synthesize this time, superior's implementation is special

- (id)initWithSuperior:(Superior *)superior {
    if ((self = [super init])) {
        superior_handle_ = [superior.handle retain];
    }
    return self;
}

- (void)dealloc {
    [superior_handle_ release];

    [super dealloc];
}

- (Superior *)superior { 
    @synchronized (superior_handle_) {
        return superior_handle_.superior; 
    }
}

@end

Einige Vorteile:

  1. Es ist sicher fädeln. Es gibt keine Möglichkeit, die schwache Referenz in nachrangigem werden ein ungültiger Zeiger enthalten haben kann. Es kann null werden, aber das ist in Ordnung.
  2. Es wird nur die Objekte selbst müssen über den eingebetteten schwachen Verweis kennen. Alle andere Objekte können mit nachrangigem behandeln, als ob es einen regelmäßigen Bezug auf Überlegene hat.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top