Reputation: 572
I'm using Nico Kreipke's FTPManager (click here to go to GiHub) to download some data from an FTP address.
The code works if it's run before the user's first interaction, after that it will usually fail (about 9 out of 10).
When it fails, the following message is written (0x_ are actually valid addresses):
request (0x_) other than the current request(0x0) signalled it was complete on connection 0x_
That message isn't written by neither my code nor by FTPManager, but by Apple's. On its GitHub, I've found some one with the same error, but the source of it could possible be the same as mine. (That person wasn't using ARC.)
If I try to print the objects of those addresses with the po
command, the console writes that there's no description available.
Also, the memory keeps adding up until the app receives a memory warning, and soon after the OS terminates it.
By pausing the app when that message appears, I can see that the main thread is in a run loop.
CFRunLoopRun();
self.ftpManager = [[FTPManager alloc] init];
[self downloadFTPFiles:@"192.168.2.1/sda1/1668"];
ftpManager
is a strong reference.
The downloadFTPFiles:
method:
- (void) downloadFTPFiles:(NSString*) basePath
{
NSLog(@"Reading contents of path: %@", basePath);
FMServer* server = [FMServer serverWithDestination: basePath username:@"test" password:@"test"];
NSArray* serverData = [self.ftpManager contentsOfServer:server];
NSLog(@"Number of items: %d", serverData.count);
for(int i=0; i < serverData.count; i++)
{
NSDictionary * sDataI = serverData[i];
NSString* name = [sDataI objectForKey:(id)kCFFTPResourceName];
NSNumber* type = [sDataI objectForKey:(id)kCFFTPResourceType];
if([type intValue] == 4)
{
NSLog(@"%@ is Folder", name);
NSString * nextDestination = [basePath stringByAppendingPathComponent: name];
[self downloadFTPFiles:nextDestination];
}
else
{
NSLog(@"%@ is File", name);
[self.ftpManager downloadFile:name toDirectory:[NSURL fileURLWithPath:NSHomeDirectory()] fromServer:server];
}
}
}
I've tried running that code on several places:
The app delegate's application:didFinishLaunchingWithOptions:
;
The viewDidLoad
, viewWillAppear:
and viewDidAppear:
of the a view controller loaded just after the app launches and a view controller presented later.
By an action triggered with a button event.
The download of the data is always well performed when executed by the delegate or a view controller loaded with the app (with an exception). But when run after the user's first interaction with the app, it'll most likely fail with the mentioned error.
The exception for view controllers loaded before the user's first interaction is when the call is in either the viewWillAppear:
or viewDidAppear:
methods. When it's called a second time (for example, a tab of a tab bar controller) it'll also, most likely, fail.
Does anyone have an idea of what may be happening, or if I'm doing something wrong? Or any alternative solution, maybe?
Any help to solve this problem will be welcomed.
Thanks,
Tiago
Upvotes: 0
Views: 572
Reputation: 572
I ended up sending the downloadFile:toDirectory:fromServer:
message inside a dispatch_async
block. I've also created an FTPManage for every file downloaded.
It worked, but I have no idea why.
I'm leaving this answer to whomever crosses with this problem.
If anyone can let me know why this technique worked, please comment bellow so I can update the answer.
Here's the new way I'm downloading each file:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
FTPManager *manager = [[FTPManager alloc] init];
[manager downloadFile:name toDirectory:[NSURL fileURLWithPath:path] fromServer:server];
});
Again, If you know why this worked, let me know.
Thanks.
Full Method
- (void) downloadFTPFiles:(NSString*) basePath
{
NSLog(@"Reading contents of path: %@", basePath);
FMServer *server = [FMServer serverWithDestination:basePath username:@"test" password:@"test"];
NSArray *serverData = [self.ftpManager contentsOfServer:server];
NSLog(@"Number of items: %d", serverData.count);
for(int i=0; i < serverData.count; i++)
{
NSDictionary *sDataI = serverData[i];
NSString *name = [sDataI objectForKey:(id)kCFFTPResourceName];
NSNumber *type = [sDataI objectForKey:(id)kCFFTPResourceType];
if([type intValue] == 4)
{
NSLog(@"%@ is Folder", name);
NSString *nextDestination = [basePath stringByAppendingPathComponent:name];
[self downloadFTPFiles:nextDestination];
}
else
{
NSLog(@"%@ is File", name);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
FTPManager *manager = [[FTPManager alloc] init];
[manager downloadFile:name toDirectory:[NSURL fileURLWithPath:path] fromServer:server];
});
}
}
}
Upvotes: 2