Objective-C에서 대기열을 어떻게 만들고 사용합니까?


107

Objective-C 프로그램에서 큐 데이터 구조를 사용하고 싶습니다. C ++에서는 STL 큐를 사용합니다. Objective-C에서 동등한 데이터 구조는 무엇입니까? 항목을 푸시 / 팝은 어떻게합니까?

답변:


153

Ben의 버전은 대기열 대신 스택이므로 약간 조정했습니다.

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

새 메서드를 사용하려는 위치에 .h 파일을 가져 와서 다른 NSMutableArray 메서드처럼 호출하면됩니다.

행운을 빕니다. 코딩을 계속하세요!


1
빈 대기열에서 대기열을 빼려고 할 때 예외를 발생시키는 대신 nil을 반환하려는 사람들을 위해 대기열에서 빼기 시작 부분에 주석 처리 된 줄을 추가했습니다. 예외를 발생시키는 NSMutableArray 동작을 따르는 IMO는 Cocoa와 더 일치합니다. 결국 -count대기열에서 제거 할 개체가 있는지 미리 전화를 걸어 확인할 수 있습니다 . 정말 선호도의 문제입니다.
Quinn Taylor

2
이 코드를 github repo에 추가했습니다. 내가 뭔가 잘못 되었다면 자유롭게 포크하거나 알려주세요 : github.com/esromneb/ios-queue-object 감사합니다 !!!
portforwardpodcast

2
내가 뭔가를 놓치고 있습니까, 아니면이 구현이 대기열에서 제거에 O (n) 복잡성을 가지고 있습니까? 끔찍합니다. 원형 배열 구현을 사용하면 훨씬 나을 것입니다. 이 구현은 작동 할 수 있지만 O (n) 대기열에서 빼는 아이디어는 고통 스럽습니다.
ThatGuy 2014-08-29

11
@Wolfcow, 인덱스 0에서 개체를 제거하면 배열의 모든 개체가 하나씩 아래로 이동합니다. 따라서 단일 항목을 제거하려면 O (n)입니다. 아마도 모바일 애플리케이션에서 99 %의 시간 인 작은 대기열에는 적합 할 수 있지만 시간이 중요한 상황에서 대규모 데이터 세트에는 끔찍한 솔루션이 될 것입니다. 다시 말하지만 대부분의 객관적인 C 상황에서 찾을 수있는 것은 아닙니다.
ThatGuy 2014 년

2
@ThatGuy 조금 늦었지만 NSArray는 순환 버퍼로 구현되므로 런타임은 theta (N)이 아닙니다.
hhanesand

33

나는 NSMutableArray를 사용하는 것이 반드시 최선의 해결책 이라고 말하지 않을 것입니다 . 특히 메서드 이름이 충돌 할 경우 발생할 수있는 취약성 때문에 범주가있는 메서드를 추가하는 경우 특히 그렇습니다. 빠르고 더러운 대기열의 경우 변경 가능한 배열의 끝에 추가하고 제거하는 메서드를 사용합니다. 그러나 큐를 재사용 할 계획이거나 코드를 더 읽기 쉽고 자명하게 만들고 싶다면 전용 큐 클래스를 사용하는 것이 좋습니다.

Cocoa에는 내장 된 옵션이 없지만 다른 옵션이 있으며 처음부터 작성할 필요가 없습니다. 끝에서 추가 및 제거 만하는 진정한 큐의 경우 원형 버퍼 배열은 매우 빠른 구현입니다. 제가 작업해온 Objective-C의 라이브러리 / 프레임 워크 인 CHDataStructures.framework를 확인하세요 . 스택, 데크, 정렬 된 세트 등의 다양한 큐 구현이 있습니다. 사용자의 목적을 위해 CHCircularBufferQueue 는 NSMutableArray를 사용하는 것보다 훨씬 빠르고 (즉, 벤치 마크로 입증 가능) 더 읽기 쉽고 (주관적 임) 더 읽기 쉽습니다 .

C ++ STL 클래스 대신 네이티브 Objective-C 클래스를 사용하는 한 가지 큰 장점은 Cocoa 코드와 원활하게 통합되고 인코딩 / 디코딩 (직렬화)에서 훨씬 더 잘 작동한다는 것입니다. 또한 가비지 수집 및 빠른 열거 (둘 다 10.5+에 있지만 iPhone에서는 후자에만 있음)와 완벽하게 작동하며 Objective-C 개체와 C ++ 개체에 대해 걱정할 필요가 없습니다.

마지막으로, NSMutableArray가 양쪽 끝에서 추가 및 제거 할 때 표준 C 배열보다 낫지 만 대기열에 대한 가장 빠른 솔루션은 아닙니다. 대부분의 응용 프로그램에서는 만족 스럽지만 속도가 필요한 경우 순환 버퍼 (또는 경우에 따라 캐시 라인을 핫 유지하도록 최적화 된 연결 목록)가 NSMutableArray를 쉽게 중단시킬 수 있습니다.


2
누군가가 실제 대기열 솔루션으로 답장을하게되어
기쁩니다

모든 링크가 끊어졌습니다. 해당 프레임 워크는 어디서 얻습니까? 좋은 내용을 많이 읽었지만 실제 코드를 찾을 수 없습니다!
amok dec

프레임 워크는 유망하게 들리지만 SVN에 대한 링크는 여전히 끊어졌습니다. 어딘가에서 코드를 얻을 기회가 있습니까? 편집 : mac.softpedia.com/progDownload/ 에서 얻었습니다. 하지만 이것이 현재 버전인지 여부를 알 수 없습니다
Kay

Dave DeLong의 Git 리포지토리 클론 은 요즘 이동하는 리포지토리로 보입니다.
Regexident

29

내가 아는 한 Objective-C는 Queue 데이터 구조를 제공하지 않습니다. 가장 좋은 방법은을 만드는 것입니다 NSMutableArray, 다음 사용 [array lastObject], [array removeLastObject]항목을 가져 오기 위해, 그리고 [array insertObject:o atIndex:0]...

이 작업을 많이 수행하는 경우 Objective-C 범주를 생성하여 NSMutableArray클래스 의 기능을 확장 할 수 있습니다 . 카테고리를 사용하면 기존 클래스 (소스가없는 클래스라도)에 동적으로 함수를 추가 할 수 있습니다. 큐를 다음과 같이 만들 수 있습니다.

(참고 :이 코드는 실제로 대기열이 아닌 스택 용입니다. 아래 설명 참조)

@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

7
여기에 대기열이 아닌 스택을 구현 한 것을 알고 있습니까?
Jim Puls

아-죄송합니다! -아래 Wolfcow의 수정 사항을 참조하십시오.
Ben Gotow

"최상의 선택"을 "가장 간단한 옵션"으로 바꾸면 동의합니다. :-) 데이터 구조 순수 주의자 및 성능 집착자는 진정한 대기열을 선호하지만 NSMutableArray는 대기열을 쉽게 나타낼 수 있습니다.
Quinn Taylor

3
대기열이 요청되었지만 스택 솔루션을 원했기 때문에 벤에게 +1 :)
whitneyland 2011-08-29

내가 생각할 수있는 것은 고통뿐입니다. 배열의 시작 부분에 개체를 삽입하는 경우 삽입 할 때마다 1 개의 공간에 모든 요소를 ​​복사해야합니다. 이 경우 연결 목록이 훨씬 더 잘 수행됩니다.
TheM00s3 2015-08-17

8

실제 큐 컬렉션 클래스는 없지만 NSMutableArray는 효과적으로 동일한 작업에 사용할 수 있습니다. 원하는 경우 편리하게 팝 / 푸시 메서드를 추가 하는 범주 를 정의 할 수 있습니다 .


사실, NSMutableArray는 꽤 괜찮은 대기열을 만듭니다.하지만 전면에서 제거하는 것이 배열 구조가 뛰어난 것은 아닙니다. 그럼에도 불구하고 작은 대기열의 경우 성능은 어쨌든 주요 관심사가 아닙니다. 내 친구는이 주제의 약 블로그에 다시 ... 잠시 sg80bab.blogspot.com/2008/05/...
퀸 테일러

7

예, NSMutableArray를 사용합니다. NSMutableArray는 실제로 2-3 트리로 구현 됩니다. 일반적으로 임의의 인덱스에서 NSMutableArray에서 개체를 추가하거나 제거하는 성능 특성에 대해 걱정할 필요가 없습니다.


1
NSArray (확장에 의한 NSMutableArray)는 클래스 클러스터입니다. 즉, 뒤에서 서로 바꿔서 사용할 수있는 여러 개인 구현이 있습니다. 일반적으로 얻는 것은 요소의 수에 따라 다릅니다. 또한 Apple은 언제든지 특정 구현의 세부 사항을 자유롭게 변경할 수 있습니다. 그러나 일반적으로 표준 어레이보다 훨씬 더 유연하다는 것이 맞습니다.
Quinn Taylor

5

re : Wolfcow-Wolfcow의 대기열에서 빼기 방법의 수정 된 구현입니다.

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

4

범주를 사용하는 솔루션 은 대기열의 상위 집합 인 작업을 노출 NSMutableArray하므로 실제 대기열이 아닙니다 NSMutableArray. 예를 들어, 대기열의 중간에서 항목을 제거 할 수 없어야합니다 (이러한 범주 솔루션에서 여전히 수행 할 수 있음). 객체 지향 디자인의 주요 원칙 인 기능을 캡슐화하는 것이 가장 좋습니다.

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

특정 기술 (예 : KVC)을 사용하면 내부 스토리지 어레이에 직접 액세스하고 조작 할 수 있지만 카테고리를 사용하는 것보다 훨씬 낫다고 주장 할 수 있습니다.
vikingosegundo

3

이것이 내 구현이며 도움이되기를 바랍니다.

최소한의 것이므로 새 헤드를 팝시 저장하고 이전 헤드를 버려서 헤드 트랙을 유지해야합니다.

@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

2

STL 대기열을 사용할 수없는 특별한 이유가 있습니까? Objective C ++는 C ++의 상위 집합입니다 (Objective C 대신 Objective C ++를 사용하려면 .m 대신 .mm을 확장자로 사용). 그런 다음 STL 또는 다른 C ++ 코드를 사용할 수 있습니다.

Objective C 개체와 함께 STL 큐 / 벡터 / 목록 등을 사용하는 한 가지 문제는 일반적으로 유지 / 해제 / 자동 해제 메모리 관리를 지원하지 않는다는 것입니다. 이는 생성시 Objective C 개체를 유지하고 파괴시 해제하는 C ++ 스마트 포인터 컨테이너 클래스로 쉽게 해결할 수 있습니다. STL 대기열에 넣는 내용에 따라 이것은 종종 필요하지 않습니다.


1
이건 정말 좋은 생각이 아닌 것 같네요 ... 뭔가 할 있다고해서 그래야한다는 뜻은 아닙니다. 큐 클래스를 위해 전체 STL 및 C ++ 에코 시스템을 가져 오는 것은 확실히 과잉입니다.
extropic-engine 2011

3
사실, 그것이 게시 된 이후로 이것은 훨씬 더 나은 아이디어가되었습니다. Objective C ++ / ARC는 Objective C 객체 포인터와 함께 STL 컨테이너를 사용할 수 있으며 모두 작동 함을 의미합니다. ARC는 C ++ 구조 내에서 자동으로 메모리 관리를 처리합니다. 나는 또한 일반적으로 C ++가 훨씬 더 나은 C이기 때문에 Objective-C ++가 일반 Objective C (예를 들어 enum 클래스와 같은 것을 제공)보다 일반적으로 더 나은 선택이라고 주장합니다. 그리고 STL / C ++를 추가하는 것이 실제 앱의 크기에 눈에 띄는 영향을 미치는지 의심합니다.
Peter N Lewis

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.