【问题标题】:Issue Connecting with GCDAsyncSocket with OSX executable使用 OSX 可执行文件连接 GCDAsyncSocket 的问题
【发布时间】:2013-03-10 18:27:59
【问题描述】:

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

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

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

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

【问题讨论】:

  • 你有一个很好的问题。但是,我删除了您问题的 Linux 部分,这确实是一个完全不同的问题。你会做一些单独的搜索并发布关于在 Linux 上使用 Objective-C、FMDB 和 GCDAsyncSocket 的新问题吗?
  • 谢谢诺亚。采取的观点 - 希望快速将 Linux 问题附加到这个问题上,是/否 GCDAsyncSocket 是否在 Linux 上工作!关于我的问题的注释:关于此问题的其他 2 个类似问题似乎表明 ARC 已删除该对象(在这种情况下将转换为对象 Device *d1),因此没有委托消息。但是,当我在 main.m while 循环中对 @continue 进行断点时,LoggerClass *logger obj 仍然与 d1 一起存在,因此它没有超出范围。谢谢。
  • Mac 防火墙有可能阻止这个吗?您是否尝试过在 localhost 上运行的服务器?另外,您是否尝试过已知工作的主机和端口,例如 HTTP 或 SMTP 服务器?
  • Erps,没关系。见下文。

标签: objective-c macos cocoaasyncsocket gcdasyncsocket


【解决方案1】:

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

查看 dispatch_get_main_queue() documentation

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

dispatch_main();

【讨论】:

  • 很好,通过放置 dispatch_main();就在while循环之前,虽然我没有替换任何代码......我应该是吗?这是放置它的最佳位置还是应该放在设备类中?感谢您的帮助。
  • 请务必阅读 dispatch_get_main_queue() 和 dispatch_main() 的文档。正如我所说,你不需要 while 循环——它不会被执行。 dispatch_main() 永远不会返回。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多