2

I have the excellent GCDAsyncSocket running perfectly on an iOS app I have developed.

I was just playing around with setting up a Mac OSX command line program that uses the library in a similar way to log to SQLite DB but can't get it to even attempt to connect to host. No errors get generated. The program doesn't crash or anything so don't have an idea about why it's not working. Does anyone have an idea why this won't work?

The console only prints out the following (with no connect/disconnect/read/write logging i.e. the socket delegate methods are not being called):

Attempting to connect to host: 192.168.1.2 on port: 1234 to refresh

Here is quite a bit of the code I am using:

main.m

#import <Foundation/Foundation.h>
#import "LoggerClass.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        LoggerClass *logger = [[LoggerClass alloc] init];
        [logger startLogging];
        while (logger.status == 0) {
            sleep(1);
            continue;
        }
        return 0;
    }
}

LoggerClass.h

#import <Foundation/Foundation.h>
#import "Device.h"

@interface LoggerClass : NSObject <DeviceProtocol>

@property (nonatomic, strong) FMDatabase *database;
@property (nonatomic, strong) NSArray *devices;
@property (nonatomic) int status;
- (void)startLogging;

@end

LoggerClass.m

#import "LoggerClass.h"
#import "FMDatabase.h"

#define kLoggingInProgress 0
#define kLoggingCompleted 1

@implementation LoggerClass

@synthesize database = _database;
@synthesize devices = _devices;
@synthesize status = _status;

- (id)init {
    if (self = [super init]) {
        self.status = kLoggingInProgress;

        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *docsPath = [paths objectAtIndex:0];
        NSString *path = [docsPath stringByAppendingPathComponent:@"database.sqlite"];  
        self.database = [FMDatabase databaseWithPath:path];

        Device *d1 = [Device deviceWithName:@"Device 1" address:@"192.168.1.2" delegate:self];      
        self.devices = [NSArray arrayWithObjects:d1, nil];
    }   
    return self;
}

- (void)startLogging {
    for (Device *d in self.devices) {
        [d refresh];
    }
}

- (void)didUpdateDevice:(Device *)device {

    // Insert DB entry code

    NSLog(@"%@ has finished Logging", device.name);
    self.status = kLoggingCompleted; // This would obviously register completed if only 1 device returned but for sake of this test that fine
}

@end

Device.h

#import <Foundation/Foundation.h>
#import "GCDAsyncSocket.h"

@protocol DeviceProtocol;

@interface Device : NSObject

@property (nonatomic, weak) id<DeviceProtocol> delegate;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *address;
@property (nonatomic, strong) GCDAsyncSocket *socket;

+ (Device *)deviceWithName:(NSString *)n address:(NSString *)a delegate:(id<DeviceProtocol>)d;
- (void)refresh;

@end

@protocol DeviceProtocol <NSObject>
@required
- (void)didUpdateDevice:(Device *)device;
@end

Device.m

#import "Device.h"

#define DEVICE_PORT 1234

@implementation Device

@synthesize delegate = _delegate;
@synthesize name = _name;
@synthesize address = _address;
@synthesize socket = _socket;

- (id)initWithName:(NSString *)name andAddress:(NSString *)address andDelegate:(id<DeviceProtocol>)delegate { // Designated Initialiser
    if (self = [super init]) {

        self.socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()];

        self.name = name;
        self.address = address;
        self.delegate = delegate;
    }
    return self;
}

+ (Device *)deviceWithName:(NSString *)n address:(NSString *)a delegate:(id<DeviceProtocol>)d {
    return [[Device alloc] initWithName:n andAddress:a andDelegate:d];
}

#pragma mark - GCD Async Socket Delegate Methods

- (void)socket:(GCDAsyncSocket *)sender didConnectToHost:(NSString *)host port:(UInt16)port {
    NSLog(@"Connected to: %@", self.address);
}

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)error {
    NSLog(@"Socket for %@ disconnected %@.", self.address, error);

    if (self.delegate) [self.delegate didUpdateDevice:self];
}

- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag {
    NSLog(@"socket:didWriteDataWithTag:");
}

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag {
    NSLog(@"socket:didReadData:withTag:");

    [self.socket disconnect];   
}

- (void)refresh {
    if ([self.address length] == 0) { [self.delegate didUpdateDevice:self]; return; }

    NSLog(@"Attempting to connect to host: %@ on port: %i to refresh", self.address, DEVICE_PORT);
    NSError *error = nil;
    if (![self.socket connectToHost:self.address onPort:DEVICE_PORT withTimeout:15 error:&error]) NSLog(@"ERROR: %@", error);

    NSData *dataToSend;
    // Build byte data here to send to device (exact same data works on iOS)

    [self.socket writeData:dataToSend withTimeout:10 tag:0];
    [self.socket readDataWithTimeout:-1 tag:0];
}

@end
4

1 回答 1

2

我刚刚重新阅读了您的评论并意识到您的 main() 是什么样子。我认为这就是你的问题所在。回调可能位于主调度队列中,但它永远没有机会执行它们。在 Cocoa 应用程序中,主队列通常作为主运行循环的一部分运行,但您不会启动运行循环。

请参阅 dispatch_get_main_queue()文档

我认为最简单的初始修复是用这个替换你的旋转循环:

dispatch_main();
于 2013-03-11T15:41:48.780 回答