2010-04-06 30 views
18

Tôi đang cố gắng sử dụng một chuỗi riêng biệt để làm việc với một số API.iPhone: cách sử dụng performSelector: onThread: withObject: waitUntilDone: method?

Vấn đề là tôi không thể sử dụng phương pháp performSelector:onThread:withObject:waitUntilDone: với chuỗi mà tôi đã khởi tạo cho điều này.

Mã của tôi:

@interface MyObject : NSObject { 
    NSThread *_myThread; 
} 
@property(nonatomic, retain) NSThread *myThread; 
@end 

@implementation MyObject 
@synthesize myThread = _myThread; 
- (NSThread *)myThread { 
    if (_myThread == nil) { 
    NSThread *myThreadTemp = [[NSThread alloc] init]; 
    [myThreadTemp start]; 
    self. myThread = myThreadTemp; 
    [myThreadTemp release]; 
    } 
    return _myThread; 
} 

- (id)init { 
    if (self = [super init]) { 
    [self performSelector:@selector(privateInit:) onThread:[self myThread] withObject:nil waitUntilDone:NO]; 
    } 
    return self; 
} 
- (void)privateInit:(id)object { 
    NSLog(@"MyObject - privateInit start"); 
} 

- (void)dealloc { 
    [_myThread release]; 
    _myThread = nil; 
    [super dealloc]; 
} 
@end 

"MyObject - privateInit start" không bao giờ được in ra.
Tôi đang thiếu gì?

Tôi đã cố gắng thực hiện chuỗi với mục tiêu và bộ chọn, cố gắng đợi để hoàn thành quá trình thực thi phương thức (waitUntilDone:YES).
Không có gì hữu ích.

CẬP NHẬT:
Tôi không cần đa luồng này để tách các hoạt động tốn kém cho một chuỗi khác.
Trong trường hợp này tôi có thể sử dụng số performSelectorInBackground như đã đề cập trong một vài câu trả lời.
Lý do chính cho luồng riêng biệt này là cần phải thực hiện tất cả các hành động trong API (TTS bởi Loquendo) từ một chuỗi duy nhất.
Có nghĩa là tôi phải tạo một thể hiện của đối tượng TTS và các phương thức gọi trên đối tượng đó từ cùng một chuỗi mọi lúc.

Trả lời

14

Tôi đã tìm thấy câu trả lời!

Để giữ thread lên, có nhu cầu ở thêm đoạn mã:

- (void)threadMain:(id)data { 
    NSAutoreleasePool *pool = [NSAutoreleasePool new]; 

    NSRunLoop *runloop = [NSRunLoop currentRunLoop]; 
    [runloop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; 

    while (isAlive) { // 'isAlive' is a variable that is used to control the thread existence... 
     [runloop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
    } 

    [pool release]; 
} 


Và dòng tiếp theo:

NSThread *myThreadTemp = [[NSThread alloc] init]; 

nên được thay thế bằng cái này:

NSThread *myThreadTemp = [[NSThread alloc] initWithTarget:self selector:@selector(threadMain:) object:nil]; 

EDIT: Như đã được đề xuất bởi một vài mọi người ở đây tôi đã thêm vài dòng mã (NSAutoreleasePool, phương thức addPort và 'boolean' isAlive).

+1

Không tạo ra một vòng lặp vô hạn theo cách đó? Nếu runloop không có gì để làm, nó sẽ bỏ ngay lập tức và tất cả những gì bạn làm là gọi '- run' thường xuyên như bộ vi xử lý của bạn có thể xử lý. (Sử dụng CPU ở 100%) – bastibe

+0

Vô hạn - có. Nhưng vòng lặp không lặp lại tất cả thời gian. Tôi đã đặt một dòng đăng nhập (NSLog ...) bên trong và nó được gọi chỉ một lần ... –

+0

Đây là hành vi bất ngờ và không nên dựa vào. Một vòng lặp chạy không có nguồn đầu vào hoặc bộ hẹn giờ được định cấu hình nên thoát ngay lập tức và do đó vòng lặp của bạn sẽ chạy liên tục, lặp đi lặp lại, sử dụng CPU 100%, như áp phích cho biết. Tham khảo tài liệu nsrunloop để biết thêm thông tin. –

1

Bạn đã tạo chuỗi nhưng chưa chạy. Nó phải chạy để thực hiện một cái gì đó.

Thay vào đó, bạn cũng có thể sử dụng "performSelectorInBackground". Nó sẽ xếp hàng lời gọi cho đến khi khởi tạo xong.

+0

Cảm ơn bạn đã bình luận của bạn. '[myThreadTemp start];' không được phép làm cho luồng chạy? 'performSelectorInBackground' không tốt cho tôi. Tôi phải sử dụng một thread cho tất cả các hoạt động trên API mà tôi sử dụng (TTS bởi Loquendo). –

+1

Trong thời gian giữa '[myThreadTemp bắt đầu];' và bộ chọn thực hiện của bạn, luồng có thể đã dừng lại. – Giao

+0

Nếu bạn cần một chuỗi riêng biệt, thì bạn có thể sử dụng "detachNewThreadSelector: toTarget: withObject:". Nó sẽ tạo và sinh ra một luồng mới sẽ bắt đầu ngay lập tức, vì vậy bạn không cần phải quan tâm đến việc tạo NSThread. –

4

Vâng, tôi cho rằng tôi đã có một giải pháp tốt hơn

- (void)run{ 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 
    running = true; 
    [[NSRunLoop currentRunLoop] addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode]; 
    while (running && [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]){ 
     //run loop spinned ones 
    } 

    [pool release]; 
} 

am i làm gì ở đây?
1) Thêm cổng mô phỏng ở đây dưới dạng Nguồn sẽ ngăn phương pháp runMode:beforeDate: thoát khỏi không xác định.
2) Phương pháp runMode:beforeDate: chặn chuỗi cho đến khi có thứ gì đó trong runLoop.

+0

Nếu tôi gọi performSelector: onThread: nhiều lần, hãy thực hiện tất cả các hàng đợi chọn của tôi? – onmyway133

12

Đây là những gì phù hợp với tôi.vòng lặp chính lấy từ tài liệu của Apple http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Multithreading/RunLoopManagement/RunLoopManagement.html#//apple_ref/doc/uid/10000057i-CH16-SW25

- (void) start { 
    self.imageSaverThread = [[[NSThread alloc] initWithTarget:self selector:@selector(imageSaverThreadMain) object:nil] autorelease]; 
    [self.imageSaverThread start]; 
} 

- (void) imageSaverKeepAlive { 
    [self performSelector:@selector(imageSaverKeepAlive) withObject:nil afterDelay:60];  
} 

- (void)imageSaverThreadMain 
{ 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    // Add selector to prevent CFRunLoopRunInMode from returning immediately 
    [self performSelector:@selector(imageSaverKeepAlive) withObject:nil afterDelay:60]; 
    BOOL done = NO; 

    do 
    { 
     NSAutoreleasePool *tempPool = [[NSAutoreleasePool alloc] init]; 
     // Start the run loop but return after each source is handled. 
     SInt32 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, YES); 

     // If a source explicitly stopped the run loop, or if there are no 
     // sources or timers, go ahead and exit. 
     if ((result == kCFRunLoopRunStopped) || (result == kCFRunLoopRunFinished)) 
      done = YES; 

     [tempPool release]; 
    } 
    while (!done); 

    [pool release]; 
} 

Hy vọng nó giúp

+0

Đây là trợ giúp. Lưu ý cách một số loại sự kiện sẽ được thêm vào để ngăn vòng lặp chạy ngay lập tức trở lại. –

Các vấn đề liên quan