it-swarm.com.de

Wie erstelle und verwende ich eine Warteschlange in Objective-C?

Ich möchte eine Warteschlangendatenstruktur in meinem Objective-C-Programm verwenden. In C++ würde ich die STL-Warteschlange verwenden. Was ist die äquivalente Datenstruktur in Objective-C? Wie schiebe ich Gegenstände?

106
MrDatabase

Bens Version ist ein Stack anstelle einer Queue, also habe ich es ein bisschen optimiert:

NSMutableArray + QueueAdditions.h

@interface NSMutableArray (QueueAdditions)
- (id) dequeue;
- (void) enqueue:(id)obj;
@end

NSMutableArray + QueueAdditions.m

@implementation NSMutableArray (QueueAdditions)
// Queues are first-in-first-out, so we remove objects from the head
- (id) dequeue {
    // if ([self count] == 0) return nil; // to avoid raising exception (Quinn)
    id headObject = [self objectAtIndex:0];
    if (headObject != nil) {
        [[headObject retain] autorelease]; // so it isn't dealloc'ed on remove
        [self removeObjectAtIndex:0];
    }
    return headObject;
}

// Add to the tail of the queue (no one likes it when people cut in line!)
- (void) enqueue:(id)anObject {
    [self addObject:anObject];
    //this method automatically adds to the end of the array
}
@end

Importieren Sie einfach die .h-Datei, wo immer Sie Ihre neuen Methoden verwenden möchten, und rufen Sie sie wie alle anderen NSMutableArray-Methoden auf.

Viel Glück und weiter so!

153
Wolfcow

Ich würde nicht sagen, dass die Verwendung von NSMutableArray notwendigerweise die beste Lösung ist, insbesondere wenn Sie Methoden mit Kategorien hinzufügen, da diese eine gewisse Zerbrechlichkeit verursachen können Methodennamen kollidieren. Für eine Quick-n-Dirty-Warteschlange würde ich die Methoden zum Hinzufügen und Entfernen am Ende eines veränderlichen Arrays verwenden. Wenn Sie jedoch vorhaben, die Warteschlange wiederzuverwenden, oder wenn Sie möchten, dass der Code besser lesbar und selbsterklärend ist, ist wahrscheinlich eine dedizierte Warteschlangenklasse das Richtige für Sie.

Cocoa hat keine eingebaute, aber es gibt andere Optionen, und Sie müssen auch keine von Grund auf neu schreiben. Für eine echte Warteschlange, die nur an den Enden hinzugefügt und entfernt wird, ist ein zirkulares Pufferarray eine extrem schnelle Implementierung. Check out CHDataStructures.framework , eine Bibliothek/ein Framework in Objective-C, an dem ich gearbeitet habe. Es hat eine Vielzahl von Implementierungen von Warteschlangen sowie Stacks, Deques, sortierten Mengen usw. Für Ihre Zwecke ist CHCircularBufferQueue wesentlich schneller (dh mit Benchmarks nachweisbar) und lesbarer (zugegebenermaßen subjektiver) als mit einem NSMutableArray.

Ein großer Vorteil der Verwendung einer systemeigenen Objective-C-Klasse anstelle einer C++ STL-Klasse besteht darin, dass sie sich nahtlos in Cocoa-Code einfügt und beim Codieren/Decodieren (Serialisieren) viel besser funktioniert. Es funktioniert auch perfekt mit Garbage Collection und schneller Aufzählung (beide in 10.5+ vorhanden, aber nur letzteres auf dem iPhone) und Sie müssen sich keine Gedanken darüber machen, was ein Objective-C-Objekt und was ein C++ -Objekt ist.

Schließlich ist NSMutableArray zwar beim Hinzufügen und Entfernen an beiden Enden besser als ein Standard-C-Array, aber nicht die schnellste Lösung für eine Warteschlange. Für die meisten Anwendungen ist dies zufriedenstellend. Wenn Sie jedoch Geschwindigkeit benötigen, kann ein NSMutableArray durch einen Umlaufpuffer (oder in einigen Fällen durch eine verknüpfte Liste, die so optimiert ist, dass die Cache-Zeilen heiß bleiben) problemlos abgerufen werden.

32
Quinn Taylor

Soweit mir bekannt ist, bietet Objective-C keine Warteschlangendatenstruktur. Am besten erstellen Sie ein NSMutableArray und verwenden dann [array lastObject], [array removeLastObject], um das Objekt abzurufen, und [array insertObject:o atIndex:0]...

Wenn Sie dies häufig tun, möchten Sie möglicherweise eine Objective-C-Kategorie erstellen, um die Funktionalität der Klasse NSMutableArray zu erweitern. Mithilfe von Kategorien können Sie vorhandenen Klassen (auch solchen, für die Sie keine Quelle haben) dynamisch Funktionen hinzufügen. Sie können eine Warteschlange wie die folgende erstellen:

(HINWEIS: Dieser Code ist eigentlich für einen Stapel, keine Warteschlange. Siehe Kommentare unten)

@interface NSMutableArray (QueueAdditions)

- (id)pop;
- (void)Push:(id)obj;

@end

@implementation NSMutableArray (QueueAdditions)

- (id)pop
{
    // nil if [self count] == 0
    id lastObject = [[[self lastObject] retain] autorelease];
    if (lastObject)
        [self removeLastObject];
    return lastObject;
}

- (void)Push:(id)obj
{
     [self addObject: obj];
}

@end
29
Ben Gotow

Es gibt keine wirkliche Klasse für Warteschlangensammlungen, aber NSMutableArray kann effektiv für dasselbe verwendet werden. Sie können eine Kategorie definieren, um Pop/Push-Methoden nach Belieben hinzuzufügen.

8

Ja, verwenden Sie NSMutableArray. NSMutableArray ist eigentlich implementiert als 2-3 Baum; In der Regel müssen Sie sich nicht mit den Leistungsmerkmalen des Hinzufügens oder Entfernens von Objekten zu beliebigen Indizes aus NSMutableArray befassen.

7
the fridge owl

re: Wolfcow - Hier ist eine korrigierte Implementierung von Wolfcows Dequeue-Methode

- (id)dequeue {
    if ([self count] == 0) {
        return nil;
    }
    id queueObject = [[[self objectAtIndex:0] retain] autorelease];
    [self removeObjectAtIndex:0];
    return queueObject;
}
5
DougW

Die Lösungen, die eine Kategorie für NSMutableArray verwenden, sind keine echten Warteschlangen, da NSMutableArray Vorgänge verfügbar macht, die eine Obermenge von Warteschlangen darstellen. Zum Beispiel sollte es Ihnen nicht gestattet sein, ein Element aus der Mitte einer Warteschlange zu entfernen (wie es diese Kategorielösungen immer noch zulassen). Es ist am besten, Funktionalität zu verkapseln, ein Hauptprinzip des objektorientierten Designs.

StdQueue.h

#import <Foundation/Foundation.h>

@interface StdQueue : NSObject

@property(nonatomic, readonly) BOOL empty;
@property(nonatomic, readonly) NSUInteger size;
@property(nonatomic, readonly) id front;
@property(nonatomic, readonly) id back;

- (void)enqueue:(id)object;
- (id)dequeue;

@end

StdQueue.m

#import "StdQueue.h"

@interface StdQueue ()

@property(nonatomic, strong) NSMutableArray* storage;

@end

@implementation StdQueue

#pragma mark NSObject

- (id)init
{
    if (self = [super init]) {
        _storage = [NSMutableArray array];
    }
    return self;
}

#pragma mark StdQueue

- (BOOL)empty
{
    return self.storage.count == 0;
}

- (NSUInteger)size
{
    return self.storage.count;
}

- (id)front
{
    return self.storage.firstObject;
}

- (id)back
{
    return self.storage.lastObject;
}

- (void)enqueue:(id)object
{
    [self.storage addObject:object];
}

- (id)dequeue
{
    id firstObject = nil;
    if (!self.empty) {
        firstObject  = self.storage.firstObject;
        [self.storage removeObjectAtIndex:0];
    }
    return firstObject;
}

@end
4
Pwner

das ist meine umsetzung, hoffe es hilft.

Ist ein bisschen minimalistisch, also müssen Sie den Überblick behalten, indem Sie den neuen Kopf bei Pop speichern und den alten Kopf verwerfen

@interface Queue : NSObject {
    id _data;
    Queue *tail;
}

-(id) initWithData:(id) data;
-(id) getData;

-(Queue*) pop;
-(void) Push:(id) data;

@end

#import "Queue.h"

@implementation Queue

-(id) initWithData:(id) data {
    if (self=[super init]) {
        _data = data;
        [_data retain];
    }
    return self;
}
-(id) getData {
    return _data;
}

-(Queue*) pop {
    return tail;
}
-(void) Push:(id) data{
    if (tail) {
        [tail Push:data];
    } else {
        tail = [[Queue alloc]initWithData:data];
    }
}

-(void) dealloc {
    if (_data) {
        [_data release];
    }
    [super release];
}

@end
3
Moxor

Gibt es einen bestimmten Grund, warum Sie die AWL-Warteschlange nicht einfach verwenden können? Objective C++ ist eine Obermenge von C++ (verwenden Sie einfach .mm als Erweiterung anstelle von .m, um Objective C++ anstelle von Objective C zu verwenden). Dann können Sie die STL oder einen anderen C++ - Code verwenden.

Ein Problem bei der Verwendung der STL-Warteschlange/-Vektor/-Liste usw. mit Objective C-Objekten besteht darin, dass sie normalerweise die Speicherverwaltung für Beibehaltung/Freigabe/Autorelease nicht unterstützen. Dies lässt sich leicht mit einer C++ Smart Pointer-Containerklasse umgehen, die ihr Objective C-Objekt beim Konstruieren beibehält und es beim Zerstören freigibt. Abhängig davon, was Sie in die AWL-Warteschlange stellen, ist dies häufig nicht erforderlich.

2
Peter N Lewis

Verwenden Sie NSMutableArray.

1
Nuoji