2012-12-02 63 views
1

我想继承NSInputStream和NSOutputStream以跟踪我传递给我的服务器的命令。这样,当我收到来自服务器的回应时,我知道它是回应的命令。当我尝试在我的子类中设置命令字符串时,出现无法识别的选择器错误。子类化NSStream

子类:

PCFInputStream.h

#import <Foundation/Foundation.h> 

@interface PCFInputStream : NSInputStream 
@property (nonatomic, strong) NSString *command; 
@end 

PCFOutputStream.h

#import <Foundation/Foundation.h> 

@interface PCFOutputStream : NSOutputStream 
@property (nonatomic, strong) NSString *command; 
@end 

的.m文件只是有命令属性合成的,所以我可以调用set命令:

以下是我在以下课程中使用的课程:

//instance vars in my class 
PCFInputStream *inputStream; 
PCFOutputStream *outputStream; 


-(void)followClass:(id)sender 
{ 
    CFReadStreamRef readStream; 
    CFWriteStreamRef writeStream; 
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef) SERVER_ADDRESS, PORT,  &readStream, &writeStream); 
    inputStream = (__bridge_transfer PCFInputStream *)readStream; 
    outputStream = (__bridge_transfer PCFOutputStream *)writeStream; 
    [inputStream setDelegate:self]; 
    [outputStream setDelegate:self]; 
    [inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 
    [outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; 
    [inputStream setCommand:[NSString stringWithFormat:@"%d,%@",[sender tag], [class classTitle]]]; 
    [inputStream open]; 
    NSString *str = [NSString stringWithFormat:@"_ADD_CLASS*%@*%@*%@*%@;", [class CRN], deviceToken, [class classLink],[class courseNumber]]; 
    [outputStream setCommand:str]; 
    [outputStream open]; 
} 

以下是错误我得到,当它运行线

[inputStream setCommand:[NSString stringWithFormat:@"%d,%@",[sender tag], [class classTitle]]]; 

-[__NSCFInputStream setCommand:]: unrecognized selector sent to instance 0x1e691170 
2012-12-01 21:56:20.777 PCF[15610:907] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFInputStream setCommand:]: unrecognized selector sent to instance 0x1e691170' 
*** First throw call stack: 
(0x3a1b73e7 0x39043963 0x3a1baf31 0x3a1b964d 0x3a111208 0xfa267 0x39585047 0x39584ffb 0x39584fd5 0x3958488b 0x39584d79 0x394a3441 0x3a18c941 0x3a18ac39 0x3a18af93 0x3a0fe23d 0x3a0fe0c9 0x3743733b 0x394ee291 0x100005 0xe7d48) 
libc++abi.dylib: terminate called throwing an exception 

可有人建议我一个简单的解决方案?我尝试将NSStreamInput实例和我的NSString *命令包装到另一个类中,但这不适用于我的目的。

谢谢!

回答

3

您不能只将NSInputStream投到PCFInputStream。该对象必须创建为PCFInputStream,并且CFStreamCReatePairWithSocketToHost不会这样做。

只需使用associated object即可在类别中附加command属性到NSInputStream。这里的类接口:

@interface NSInputStream (PCFCommand) 
@property (nonatomic) NSString *pcf_command; 
@end 

你实现它是这样的:

#import <objc/runtime.h> 

@implementation NSInputStream (PCFCommand) 

static int kPCFCommandKey; 

- (NSString *)pcf_command { 
    return objc_getAssociatedObject(self, &kPCFCommandKey); 
} 

- (void)setPcf_command:(NSString *)pcf_command { 
    objc_setAssociatedObject(self, &kPCFCommandKey, [pcf_command copy], 
     OBJC_ASSOCIATION_RETAIN_NONATOMIC); 
} 

@end 
+0

嗨,你的例子非常有帮助。我只是不知道在哪里放这个声明..我从来没有使用过类别。 – kamran619

+0

从菜单栏中选择新建>文件。然后从Cocoa Touch模板中选择Objective-C类别。命名“PCFCommand”类别并将其设置为“NSInputStream”的类别。您需要在任何要访问该属性的文件中导入“NSInputStream + PCFCommand.h”。重复“NSOutputStream”。 –

+0

完美。我只是在你输入的时候发现了这个。未找到方法'objc_getAssociatedObject'。此外,常量'OBJC_ASSOCIATION_RETAIN_NONATOMIC'也不起作用。 – kamran619

1

CFStreamCreatePairWithSocketToHost创建CFWriteStreamCFReadStream。这些免费电话分别与NSOutputStreamNSInputStream桥接。所以你得到的是一个NSOutputStream和一个NSInputStream。无论你是否声明了这些子类都没有区别,这些是CFStreamCreatePairWithSocketToHost创建的类。

如果因为任何原因无法使用包装,则需要重新实现Core Foundation函数以创建自定义子类。在实践中,我建议你只包装NS[Output/Input]Stream并使用forwardingTargetForSelector:,这样你就可以在任何地方提供你的包装,其中一个原始物体是可以接受的。

+0

我可能错误地包裹类。你介意给我一个非常简单的例子吗?我把它们封装在一个NSObject中最初 – kamran619

+0

我无法让包装工作,但如果我真的包装它们,在委托方法handleEvent中,我如何获得流发送的命令..因为handleEvent委托方法提供了一个NSStream对象,而不是我的自定义对象与它的字符串命令。 – kamran619