2012-05-24 8 views
9

Używam (i jestem zobowiązany do używania) schematu innej firmy, do którego nie mam źródła. Struktura zewnętrzna obsługuje tworzenie uwierzytelnionego połączenia klient/serwer i przekazuje parę otwartych NSStreams.Czy można określić NSRunLoop/NSThread, który jest powiązany z otwartym NSStream?

Proces tworzenia strumienia w dokumentach Apple to: alloc/init, ustaw delegata, harmonogram w pętli uruchamiania i otwórz. Dokumenty Apple idą dalej, mówiąc: "Nigdy nie powinieneś próbować uzyskać dostęp do zaplanowanego strumienia z wątku innego niż ten, który posiada pętlę uruchamiania strumienia." https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html#//apple_ref/doc/uid/20002273-1001844

Proces usuwania strumienia jest następujący: zamknij, niezaplanuj, zwolnij.

Jeśli tworzy się strumień samodzielnie, jest jasne, gdzie został zaplanowany strumień. Jeśli struktura zewnętrzna tworzy strumień, może nie wiedzieć, gdzie został zaplanowany strumień.

Przeglądając dokumentację, którą znalazłem, nie widziałem sposobu, aby programowo określić NSRunLoop i NSThread, z którymi związany jest otwarty NSStream. Czy istnieje sposób na określenie tych informacji w czasie wykonywania?

+0

Edytor usunął tag środowiska wykonawczego Objective-C, ale nie zaoferował odpowiedzi na to pytanie. Sądzę, że jeśli istnieje odpowiedź, to bardzo dobrze może ona obejmować przesłuchanie środowiska wykonawczego. Dlatego pozostaw tag środowiska wykonawczego bez zmian. – xyzzycoder

+1

Myślenie, że użytkownik może leżeć w określonej domenie, nie oznacza, że ​​_question_ powinno być tak oznaczone. Środowisko wykonawcze ObjC ma niższy poziom (lub przynajmniej inny) niż wątki, strumienie i pętle uruchomieniowe - są to koncepcje framework. –

+0

Czy potrafisz nazwać framework? Czy znasz rzeczywistą klasę obiektów strumienia? 'NSInput' /' OutputStream' lub niestandardowa podklasa? –

Odpowiedz

3

Mam zamiar podać kod, który będzie prawdopodobnie pracy i powinien być używany z ostrożnością.

Definiujemy następujące kategorię Klasa:

@interface TheSpecificNSStreamClass (ProposedCategory) 

@property (nonatomic, strong, readonly) NSArray* associatedRunLoops; 

- (void)myScheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; 
- (void)myRemoveFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode; 

@end 

i realizacja:

@implementation TheSpecificNSStreamClass (ProposedCategory) 

- (NSArray*)associatedRunLoops 
{ 
    return [NSArray arrayWithArray:objc_getAssociatedObject(self, @"___associatedRunloops")]; 
} 

- (void)myScheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode 
{ 
    NSMutableArray* runloops = objc_getAssociatedObject(self, @"___associatedRunloops"); 

    if(runloops == nil) 
    { 
     runloops = [NSMutableArray array]; 
     objc_setAssociatedObject(obj, @"___associatedRunloops", runloops, OBJC_ASSOCIATION_RETAIN); 
    } 

    [runloops addObject:aRunLoop]; 

    [self myScheduleInRunLoop:aRunLoop forMode:mode]; 
} 

- (void)myRemoveFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode 
{ 
    NSMutableArray* runloops = objc_getAssociatedObject(self, @"___associatedRunloops"); 

    [runloops removeObject:aRunLoop]; 

    [self myRemoveFromRunLoop:aRunLoop forMode:mode]; 
} 

@end 

Teraz, w pewnym miejscu w delegata aplikacji, używamy metody swizzling wymieniać dwa oryginalne sposoby z naszymi realizacja:

Method origMethod = class_getInstanceMethod([TheSpecificNSStreamClass class], @selector(scheduleInRunLoop:forMode:)); 
Method altMethod = class_getInstanceMethod([TheSpecificNSStreamClass class], @selector(myScheduleInRunLoop:forMode:)); 
if ((origMethod != nil) && (altMethod != nil)) 
{ 
    method_exchangeImplementations(origMethod, altMethod); 
} 

origMethod = class_getInstanceMethod([TheSpecificNSStreamClass class], @selector(removeFromRunLoop:forMode:)); 
altMethod = class_getInstanceMethod([TheSpecificNSStreamClass class], @selector(myRemoveFromRunLoop:forMode:)); 
if ((origMethod != nil) && (altMethod != nil)) 
{ 
    method_exchangeImplementations(origMethod, altMethod); 
} 

Powstały tablica będzie mieć wszystko powiązane s. NSRunLoop.

+0

To sprytny pomysł i na pewno warto spróbować! –

+0

@Leo Natan Dziękuję. Po utworzeniu NSStream istnieje specyficzna sekwencja (na dokumenty Apple) do inicjalizacji, w tym planowanie NSStream w określonej pętli uruchamiania (oraz powiązanie, wątek) - scheduleInRunLoop: forMode :. Dokumenty Apple mówią także: "Nigdy nie powinieneś próbować uzyskać dostęp do zaplanowanego strumienia z wątku innego niż ten, który posiada pętlę uruchamiania strumienia." Tak więc wyzwaniem, które próbuję rozwiązać, jest to, czy istnieje mechanizm do przesłuchania NSStream (lub wątków/uruchom pętli), aby zrozumieć, gdzie zaplanowano NSStream? – xyzzycoder

+0

Zaktualizuję moją odpowiedź, aby użyć tej metody nieco później. –

Powiązane problemy