9

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

根据 Apple 的文档,流创建过程是:alloc/init、设置委托、在运行循环中调度和打开。Apple 的文档进一步说:“您永远不应该尝试从与拥有流的运行循环的线程不同的线程访问预定的流。” https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Streams/Articles/ReadingInputStreams.html#//apple_ref/doc/uid/20002273-1001844

流处理过程为:关闭、取消调度、释放。

如果一个人自己创建了一个流,那么很清楚该流是在哪里安排的。如果第三方框架创建了流,则可能不知道流的调度位置。

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

4

1 回答 1

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。

于 2012-05-27T18:55:28.433 回答