是否可以确定与打开的NSStream相关联的NSRunLoop / NSThread?

时间:2012-05-24 15:04:32

标签: ios macos nsthread nsstream

我正在使用(并且需要使用)我没有来源的第三方框架。第三方框架处理创建经过身份验证的客户端/服务器连接并回送一对打开的NSStream。

根据Apple的文档,流创建过程是:alloc / init,set delegate,schedule in run loop,open。 Apple的文档更进一步说:“你永远不应该尝试从与拥有流的运行循环的线程不同的线程访问预定的流。” https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html#//apple_ref/doc/uid/20002273-1001844

流处理流程为:关闭,取消预定,释放。

如果自己创建了一个流,则可以清楚地预定流的位置。如果第三方框架创建了流,则可能无法知道流的调度位置。

查看我找到的文档,我没有看到以编程方式确定与开放NSStream关联的NSRunLoop和NSThread的方法。有没有办法在运行时确定这些信息?

1 个答案:

答案 0 :(得分:3)

我将提供一个代码,可能可以正常工作,应该谨慎使用。

我们定义以下类别:

@interface TheSpecificNSStreamClass (ProposedCategory)

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

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

@end

和实施:

@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

现在,在应用程序委托中的某个位置,我们使用方法调配来将两个原始方法与我们的实现交换:

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);
}

生成的数组将包含所有关联的NSRunLoop s。