我正在使用iOS的FTP库(nkreipke/FTPManager)。它很棒。我可以下载目录列表,上传图像等。 问题是如果你让应用程序打开5分钟,什么都不做,然后你尝试下载或上传,没有任何反应。
我一直在调试它,发现NSStreamDelegate方法 - (void)stream:(NSStream *)theStream handleEvent:(NSStreamEvent)streamEvent 永远不会在那个短暂的不活动的时间。
以下是代码:
- (NSArray*) _contentsOfServer:(FMServer*)server {
BOOL success = YES;
action = _FMCurrentActionContentsOfServer;
fileSize = 0;
self.directoryListingData = [[NSMutableData alloc] init];
NSURL* dest = [server.destination ftpURLForPort:server.port];
And(success, (dest != nil));
Check(success);
if (![dest.absoluteString hasSuffix:@"/"]) {
//if the url does not end with an '/' the method fails.
//no problem, we can fix this.
dest = [NSURL URLWithString:[NSString stringWithFormat:@"%@/",dest.absoluteString]];
}
CFReadStreamRef readStream = CFReadStreamCreateWithFTPURL(NULL, (__bridge CFURLRef)dest);
And(success, (readStream != NULL));
if (!success) return nil;
self.serverReadStream = (__bridge_transfer NSInputStream*) readStream;
And(success, [self.serverReadStream setProperty:server.username forKey:(id)kCFStreamPropertyFTPUserName]);
And(success, [self.serverReadStream setProperty:server.password forKey:(id)kCFStreamPropertyFTPPassword]);
if (!success) return nil;
self.bufferOffset = 0;
self.bufferLimit = 0;
currentRunLoop = CFRunLoopGetCurrent();
self.serverReadStream.delegate = self;
[self.serverReadStream open];
[self.serverReadStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
CFRunLoopRun(); //<- Hangs here.
And(success, streamSuccess);
if (!success) return nil;
NSArray* directoryContents = [self _createListingArrayFromDirectoryListingData:self.directoryListingData];
self.directoryListingData = nil;
return directoryContents;
serverReadStream是 NSInputStream 对象。
当行动结束时:
if (self.serverReadStream) {
[self.serverReadStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
CFRunLoopStop(CFRunLoopGetCurrent());
self.serverReadStream.delegate = nil;
[self.serverReadStream close];
self.serverReadStream = nil;
}
此代码位于 FTPManager.m 。我一直在寻找互联网上的答案,但无法找到任何答案。我不知道为什么NSStreamDelegate方法在经常使用时会被调用,但是在一段时间不活动之后,它就不会被调用。
如果有人可以帮助我,那就太好了。
感谢。
答案 0 :(得分:1)
我在我的iPad应用程序中使用相同的库,当我在恢复应用程序时尝试刷新FTP服务器内容时,我被困在同一个CFRunLoopRun()调用中。
我必须对FTPManager代码进行两处更改。
首先,我改变了
的顺序[self.serverReadStream open];
[self.serverReadStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
到
[self.serverReadStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.serverReadStream open];
原因是流不能打开。在打开调用期间引发错误事件,但如果流未调度到运行循环,我们将永远不会收到错误事件。因此,在打开之前安排将允许我们获取错误事件。
我的案例中需要的另一个更改是禁用持久连接。似乎在设备的挂起/恢复周期之后,流使用的内部套接字会变得很小,并且在尝试访问它时总是返回错误。
在流配置中添加以下行已经解决了我的问题:
[self.serverReadStream setProperty: (id) kCFBooleanFalse forKey: (id) kCFStreamPropertyFTPAttemptPersistentConnection];
希望这有帮助。