objective-c - 使用 OSX 可执行文件连接 GCDAsyncSocket 时出现问题

标签 objective-c macos cocoaasyncsocket gcdasyncsocket

我在我开发的 iOS 应用程序上完美运行了出色的 GCDAsyncSocket。

我只是在尝试设置一个 Mac OSX 命令行程序,该程序以类似的方式使用该库来登录 SQLite DB,但无法让它尝试连接到主机。不会产生任何错误。该程序不会崩溃或发生任何事情,因此不知道为什么它不工作。有谁知道为什么这行不通?

控制台仅打印出以下内容(没有连接/断开/读/写日志记录,即未调用套接字委托(delegate)方法):

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

这是我正在使用的相当多的代码:

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

最佳答案

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

参见dispatch_get_main_queue() documentation .

我认为最简单的初始修复方法是将你的自旋循环替换为:

dispatch_main();

关于objective-c - 使用 OSX 可执行文件连接 GCDAsyncSocket 时出现问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15325886/

相关文章:

swift - 我无法使用 protobuf-swift CodeOutputStream 将流写入 NSData?

ios - 编写流时遇到麻烦

objective-c - 用于启动带有参数的应用程序的 Cocoa 代码

javascript - Automator Javascript - "Choose From List"返回值

ios - 无法从 CVMetalTextureGetTexture 函数获取有效的 MTLTexture

objective-c - 将上下文添加到 UI 控件或 NSObject

macos - 导入 matplotlib 时 numpy 的版本错误

ios - 在 Swift 中使用 CocoaAsyncSocket 接收 SSDP 响应

ios - dismissViewControllerAnimated 仅在第二次点击 TableView Row 后才有效

objective-c - 可变对象与不可变对象(immutable对象)的性能