8

プログラムでCFStreamCreatePairWithSocketToHostを使用するとランダムなEXC_BADACCESSエラーが発生することに気付きましたが、ios6でのみ-ios5シミュレーターを使用すると(xcode4.5でios6sdk内であっても)すべて正常に動作します。私は最終的に、問題を次の小さなテスト プログラムに抽出しました。これでガード malloc を有効にすると、すぐに爆発します (以下のクラッシュを参照)。また、これはアークと非アークで発生します。

@interface PHAppDelegate : UIResponder <UIApplicationDelegate, NSStreamDelegate>
{
    NSOutputStream*     mOutputStream;
    NSInputStream*      mInputStream;
}

@implementation PHAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSString* testAddress = @"192.168.1.0";
    [self openWithHost:testAddress port:444];
    return YES;
}

- (void)openWithHost:(NSString*)host port:(int)port
{
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;

    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault,
                                       (CFStringRef)host, /*ip_addr*/
                                       port,
                                       &readStream,
                                       &writeStream);

    mInputStream = (NSInputStream *)readStream;
    mOutputStream = (NSOutputStream *)writeStream;

    if (mInputStream == nil)
    {
        NSLog(@"couldn't create the inputStream using CFStreamCreatePairWithSocketsToHost()");
        return;
    }

    if (mOutputStream == nil)
    {
        NSLog(@"couldn't create the outputstream using CFStreamCreatePairWithSocketsToHost()");
        return;
    }

    [mInputStream setDelegate:self];
    [mOutputStream setDelegate:self];

    [mInputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [mOutputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

    [mInputStream open];
    [mOutputStream open];
}

#pragma mark NSStream delegate methods

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    NSLog(@"stream-handleEvent");
}

@end

com.apple.networking.connection スレッドでのクラッシュ:

#0  0x04b35140 in tcp_connection_destination_prepare_complete ()
#1  0x04b34fee in tcp_connection_destination_start ()
#2  0x04b34c2b in tcp_connection_start_next_destination ()
#3  0x04b33c70 in tcp_connection_handle_reachability_changed ()
#4  0x04b30a95 in __tcp_connection_start_block_invoke_0 ()
#5  0x049fa53f in _dispatch_call_block_and_release ()
#6  0x04a0c014 in _dispatch_client_callout ()
#7  0x049fc418 in _dispatch_queue_drain ()
#8  0x049fc2a6 in _dispatch_queue_invoke ()
#9  0x049fd280 in _dispatch_root_queue_drain ()
#10 0x049fd450 in _dispatch_worker_thread2 ()
#11 0x94e7de12 in _pthread_wqthread ()
#12 0x94e65cca in start_wqthread ()

EXC_BADACCESS @ address 0x04b35140
0x04b3513b  <+0072>  call   0x4b332de <tcp_connection_destination_list_remove>
0x04b35140  <+0077>  mov    0x28(%esi),%eax
0x04b35143  <+0080>  test   %eax,%eax
4

1 に答える 1

0

iOS 5.x と iOS 6.x で動作する非常によく似たコードがあります。唯一の違いは、呼び出しの前にCFReadStreamRefandCFWriteStreamRefを初期化し、アロケータを渡すことです。また、便宜上、通常はコードを NSStream のカテゴリとして追加します。したがって、コードは次のようになります。NULLCFStreamCreatePairWithSocketToHostNULL

+ (void)createStreamsToHostNamed:(NSString*)hostName port:(NSInteger)port inputStream:(NSInputStream* __autoreleasing *)inputStream outputStream:(NSOutputStream* __autoreleasing *)outputStream {
    CFReadStreamRef readStream = NULL;
    CFWriteStreamRef writeStream = NULL;

    // Create a pair of of streams for a socket to the host specified
    CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)hostName, port, &readStream, &writeStream);

    // Assign the output parameters
    *inputStream  = (__bridge_transfer NSInputStream*)readStream;
    *outputStream = (__bridge_transfer NSOutputStream*)writeStream;
}

次のようなコードでメソッドを呼び出します。

@interface SomeClass : NSObject <NSStreamDelegate>
@end

@implementation SomeClass {
    NSInputStream* _inputStream;
    NSOutputStream* _outputStream;
}

- (void)_setupMethod {
    __autoreleasing NSInputStream* autoreleasingInputStream = nil;
    __autoreleasing NSOutputStream* autoreleasingOutputStream = nil;
    [NSStream createStreamsToHostNamed:kHostConstant port:kPortConstant inputStream:&autoreleasingInputStream outputStream:&autoreleasingOutputStream];

    if(autoreleasingInputStream != nil && autoreleasingOutputStream != nil) {
        _inputStream = autoreleasingInputStream;
        [_inputStream setDelegate:self];
        [_inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
        _outputStream = autoreleasingOutputStream;
        [_outputStream setDelegate:self];
        [_outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

        [_inputStream open];
        [_outputStream open];
    }
}

// NSStreamDelegate methods ...

@end
于 2013-08-09T05:45:37.820 に答える