Objective-C programımda bir kuyruk veri yapısı kullanmak istiyorum. C ++ 'da STL kuyruğunu kullanırım. Objective-C'deki eşdeğer veri yapısı nedir? Öğeleri nasıl itebilirim / çıkarabilirim?
Objective-C programımda bir kuyruk veri yapısı kullanmak istiyorum. C ++ 'da STL kuyruğunu kullanırım. Objective-C'deki eşdeğer veri yapısı nedir? Öğeleri nasıl itebilirim / çıkarabilirim?
Yanıtlar:
Ben'in sürümü bir kuyruk yerine bir yığın, bu yüzden biraz değiştirdim:
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
Yeni yöntemlerinizi kullanmak istediğiniz her yerde .h dosyasını içe aktarın ve diğer NSMutableArray yöntemlerinde olduğu gibi onları çağırın.
İyi şanslar ve Kodlamaya Devam Et!
NSMutableArray kullanmanın mutlaka en iyi çözüm olduğunu söyleyemem , özellikle de yöntem isimleri çakışırsa neden olabilecekleri kırılganlık nedeniyle kategoriler içeren yöntemler ekliyorsanız. Hızlı ve kirli bir kuyruk için, değiştirilebilir bir dizinin sonuna ekleme ve çıkarma yöntemlerini kullanırdım. Bununla birlikte, kuyruğu yeniden kullanmayı planlıyorsanız veya kodunuzun daha okunaklı ve açık olmasını istiyorsanız, muhtemelen istediğiniz şey özel bir kuyruk sınıfıdır.
Cocoa'da yerleşik bir tane yok, ancak başka seçenekler de var ve sıfırdan bir tane de yazmanız gerekmiyor. Yalnızca uçlardan eklenen ve çıkaran gerçek bir kuyruk için, dairesel bir tampon dizisi son derece hızlı bir uygulamadır. Check out CHDataStructures.framework , ben üzerinde çalıştığımızı zaten Objective-C bir kütüphane / çerçeve. Bir dizi kuyruk uygulamasının yanı sıra yığınlar, sıralar, sıralı kümeler vb. De vardır. Sizin amaçlarınız için, CHCircularBufferQueue NSMutableArray kullanmaktan önemli ölçüde daha hızlıdır (yani kıyaslamalarla kanıtlanabilir) ve daha okunabilirdir (kuşkusuz özneldir).
C ++ STL sınıfı yerine yerel bir Objective-C sınıfı kullanmanın büyük bir avantajı, Cocoa koduyla sorunsuz bir şekilde entegre olması ve kodlama / kod çözme (serileştirme) ile çok daha iyi çalışmasıdır. Aynı zamanda çöp toplama ve hızlı numaralandırma ile mükemmel çalışır (her ikisi de 10.5+ sürümünde bulunur, ancak yalnızca iPhone'da bulunur) ve Objective-C nesnesinin ne olduğu ve C ++ nesnesinin ne olduğu konusunda endişelenmenize gerek yoktur.
Son olarak, NSMutableArray, her iki uçtan ekleyip çıkarırken standart bir C dizisinden daha iyi olmasına rağmen, aynı zamanda bir kuyruk için en hızlı çözüm değildir. Çoğu uygulama için tatmin edicidir, ancak hıza ihtiyacınız varsa, dairesel bir arabellek (veya bazı durumlarda önbellek hatlarını sıcak tutmak için optimize edilmiş bir bağlantılı liste) bir NSMutableArray'i kolayca geçebilir.
Bildiğim kadarıyla, Objective-C bir Queue veri yapısı sağlamıyor. Yapabileceğiniz en iyi şey bir yaratmaktır NSMutableArray
ve sonra kullanmak [array lastObject]
, [array removeLastObject]
öğeyi almak için, ve [array insertObject:o atIndex:0]
...
Bunu çok yapıyorsanız, NSMutableArray
sınıfın işlevselliğini genişletmek için bir Objective-C kategorisi oluşturmak isteyebilirsiniz . Kategoriler, mevcut sınıflara (kaynağına sahip olmadığınız sınıflara bile) dinamik olarak işlevler eklemenize izin verir - şunun gibi bir sıra oluşturabilirsiniz:
(NOT: Bu kod aslında bir sıra için değil, yığın içindir. Aşağıdaki yorumlara bakın)
@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
Gerçek kuyruk toplama sınıfı yoktur, ancak NSMutableArray aynı şey için etkili bir şekilde kullanılabilir. İsterseniz kolaylık olması açısından pop / push yöntemleri eklemek için bir kategori tanımlayabilirsiniz .
Evet, NSMutableArray kullanın. NSMutableArray aslında bir uygulamaya 2-3 ağaç olarak; NSMutableArray'den rasgele indekslerde nesne eklemenin veya kaldırmanın performans özellikleriyle genellikle ilgilenmeniz gerekmez.
Üzerinde bir kategori kullanan çözümler NSMutableArray
gerçek kuyruklar değildir, çünkü kuyrukların NSMutableArray
bir üst kümesi olan işlemleri ortaya çıkarır. Örneğin, kuyruğun ortasından bir öğeyi kaldırmanıza izin verilmemelidir (bu kategori çözümleri hala yapmanıza izin verdiği için). En iyisi, nesne yönelimli tasarımın temel ilkelerinden biri olan işlevselliği kapsüllemek.
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
bu benim uygulamam, umarım yardımcı olur.
Biraz minimalisttir, bu yüzden yeni kafayı popta kaydedip eski kafayı atarak kafanın izini sürmelisiniz.
@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
STL kuyruğunu kullanmamanın belirli bir nedeni var mı? Objective C ++, C ++ 'ın bir üst kümesidir (yalnızca, Objective C yerine Objective C ++ kullanmak için .m yerine uzantı olarak .mm kullanın). Daha sonra STL veya başka bir C ++ kodunu kullanabilirsiniz.
STL kuyruğunu / vektörünü / listesini vb. Objective C nesneleriyle kullanmanın bir sorunu, genellikle bellek yönetimini tut / serbest bırak / otomatik bırakmayı desteklememeleridir. Bu, inşa edildiğinde Objective C nesnesini tutan ve yok edildiğinde serbest bırakan bir C ++ Smart Pointer konteyner sınıfı ile kolayca çözülür. STL kuyruğuna ne koyduğunuza bağlı olarak bu genellikle gerekli değildir.
-count
kuyruğundan çıkarılacak herhangi bir nesne olup olmadığını kontrol etmek için önceden arayabilirsiniz . Bu bir tercih meselesi, gerçekten.