2011-02-05 4 views
2

У меня есть странная проблема, пытающаяся использовать AsyncSocket. В моем приложении мне действительно нужны синхронные сокеты, потому что я обрабатываю всю связь в фоновом режиме на другом уровне. Поэтому я пытаюсь написать оболочку вокруг класса AsyncSocket SyncSocket. Вот код:AsyncSocket не вызывает делегатов

// SyncSocket.h 
#import <Foundation/Foundation.h> 
#import "AsyncSocket.h" 

@interface SyncSocket : NSObject <AsyncSocketDelegate> { 
    AsyncSocket* _asyncSocket; 
    NSTimeInterval _connectTimeout; 
    NSTimeInterval _readTimeout; 
    NSTimeInterval _writeTimeout; 
    BOOL _waiting; 
    BOOL _nsLog; 
} 

@property (nonatomic, assign) BOOL waiting; 
@property (nonatomic, assign) BOOL nsLog; 

- (id) initWithConnectTimeout: (NSTimeInterval) connectTimeout readTimeout: (NSTimeInterval) readTimeout writeTimeout: (NSTimeInterval) writeTimeout; 

- (BOOL) connectToHost: (NSString*) host onPort: (UInt16) port; 

@end 

// SyncSocket.m 
#import "SyncSocket.h" 

@implementation SyncSocket 
@synthesize waiting = _waiting; 
@synthesize nsLog = _nsLog; 

// 
// Constructor/destructor 
// 

- (id) initWithConnectTimeout: (NSTimeInterval) connectTimeout readTimeout: (NSTimeInterval) readTimeout writeTimeout: (NSTimeInterval) writeTimeout { 
    [super init]; 
    if (self == nil) 
     return self; 

    _connectTimeout = connectTimeout; 
    _readTimeout = readTimeout; 
    _writeTimeout = writeTimeout; 
    _waiting = NO; 

    _asyncSocket = [[AsyncSocket alloc] initWithDelegate: self]; 

    return self; 
} 

- (void) dealloc { 
    [_asyncSocket release]; 
    [super dealloc]; 
} 

- (BOOL) connectToHost: (NSString*) host onPort: (UInt16) port { 
    if (self.nsLog) 
     NSLog (@"connectToHost: %@ onPort: %d", host, port); 

    _waiting = YES; 
    NSError* err = nil; 
    if (![_asyncSocket connectToHost: host 
         onPort: port 
        withTimeout: _connectTimeout 
        error: &err]) 
     return NO; 

    while (self.waiting && [_asyncSocket isConnected] == NO) { 
     [NSThread sleepForTimeInterval: 0.01]; 
    } 


    return [_asyncSocket isConnected]; 
} 

- (void) writeData: (NSData*) data { 
    _waiting = YES; 
    [_asyncSocket writeData: data withTimeout: _writeTimeout tag: 0]; 

    while (self.waiting) { 
     [NSThread sleepForTimeInterval: 0.01]; 
    } 
} 


// 
// AsyncSocket delegates 
// 
- (BOOL)onSocketWillConnect:(AsyncSocket *)sock { 
    if (self.nsLog) 
     NSLog (@"onSocketWillConnect:"); 
    return YES; 
} 

- (void)onSocket:(AsyncSocket *)sock didWriteDataWithTag:(long)tag { 
    if (self.nsLog) 
     NSLog (@"didWriteDataWithTag: %d", tag); 
    _waiting = NO; 
} 

- (void) onSocket: (AsyncSocket*) sock willDisconnectWithError: (NSError*) err { 
    if (self.nsLog) 
     NSLog (@"willDisconnectWithError: %d", [err code]); 

    _waiting = NO; 
} 

- (void) onSocket: (AsyncSocket*) sock didConnectToHost: (NSString*) host port: (UInt16) port { 
    if (self.nsLog) 
     NSLog (@"didConnectToHost: %@ port: %d", host, port); 

    _waiting = NO; 
} 

@end 

Проблема заключается в том: AsyncSocket подключается к хосту просто отлично, но мой делегат didConnetToHost никогда не вызывается. И если я отлаживаю код AsyncSocket, я вижу, что даже если делегат установлен, respondsToSelector терпит неудачу. Похоже, что есть какое-то странное нарушение памяти или что-то в этом роде, но я понятия не имею, где я ошибся.

Любые идеи? Есть ли хороший пример того, как привязать AsyncSocket к синхронному сокету?

PS: Просто быть ясным: XCode 3.2.5, iPhone Simulator 4.2.

Обновление: Причина, по которой я пытаюсь связать ее с SyncSocket, заключается в том, что я хотел скрыть все делегированные элементы сокета из бизнес-логики приложения. Мне нужно использовать соединение сокетов во многих разных местах, и я не хочу реализовывать функции сокетов на низком уровне (например, обнаружение состояния сокета, получение заголовка сообщения, затем тело и т. Д.) Во многих разных местах. Я хочу иметь простой интерфейс, где я могу открывать/отправлять/получать и не беспокоиться о реализации на низком уровне. Я понимаю, что сетевое подключение должно выполняться в отдельном потоке, и это прекрасно - сделать одного фонового рабочего в основном потоке не представляет проблемы.

Таким образом, я взял образец InterfaceTest из репозитория AsyncSocket в качестве отправной точки. Оттуда удалены связанные с DNS материалы. Работает отлично. didConnect вызывается, все блестяще.

Затем я добавил проект в реализацию SyncSocket, чтобы узнать, что с ним не так. Проект можно скачать здесь: http://dl.dropbox.com/u/6402890/NetworkTest.zip - может быть, кто-то может сказать мне, что я делаю неправильно - у меня такое ощущение, что я не использую нити правильно в SyncSocket.

Если я использую в ожидании цикла как asyncSocket is Connected и мой внутренний self.waiting - она ​​выйдет из этого цикла и didConnect называется (но после цикла завершен). Если я пытаюсь использовать только мой self.waiting, который установлен в didConnect - didConnect никогда не звонил и приложение зависает.

Кто-нибудь может сказать мне, что случилось?

+0

Это не имеет никакого значения. Странная вещь - после вызова метода connect - onSocketWillConnect вызывается, а затем ничего. Я выхожу из цикла, потому что isConnected становится TRUE. – sha

+0

изменить свой метод init: if (self = [super init]) {/ * initialization * /} return self; – Felix

+0

Пробовал. Ничего не изменит. Это эквивалентно тому, что я имел, насколько я понимаю. – sha

ответ

1

Обнаружена проблема. Похоже, что я должен был изменить ждущий цикл с помощью:

[[NSThread sleepForTimeInterval: 0.01] 

Для использования RunLoop:

[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]]; 
+0

Я просто хотел поблагодарить вас, поскольку я застрял с той же проблемой в течение 2 дней. Нигде в GCDAsyncSockets это не упоминается, и для нас, новичков, это очень запутанно. Мой код будет выполняться отлично, но делегаты будут вызваны только после отключения сокета, а очередь делегатов будет равна нулю. Еще раз спасибо, вы спасли мой день! –

+0

Без проблем :) Рад, что это помогло кому-то еще – sha

Смежные вопросы