Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios URLSessiondFinisheventsforBackgroundURLSession未调用-Objective-C_Ios_Objective C_Xcode_Nsurlsession_Nsurlsessiondownloadtask - Fatal编程技术网

Ios URLSessiondFinisheventsforBackgroundURLSession未调用-Objective-C

Ios URLSessiondFinisheventsforBackgroundURLSession未调用-Objective-C,ios,objective-c,xcode,nsurlsession,nsurlsessiondownloadtask,Ios,Objective C,Xcode,Nsurlsession,Nsurlsessiondownloadtask,nsursession委托方法 urlsessiondFinisheventsforBackgroundurlsession未调用 我已经在项目功能设置中启用了后台模式 这是代码 AppDelegate.h方法 @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @property (nonatomic, copy)

nsursession
委托方法
urlsessiondFinisheventsforBackgroundurlsession
未调用

我已经在项目功能设置中启用了后台模式

这是代码

AppDelegate.h方法

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (nonatomic, copy) void(^backgroundTransferCompletionHandler)();

@end
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{

    self.backgroundTransferCompletionHandler = completionHandler;

}
- (void)viewDidLoad
{
    [super viewDidLoad];
    //Urls
    [self initializeFileDownloadDataArray];

    NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
    self.docDirectoryURL = [URLs objectAtIndex:0];

    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.GACDemo"];
    sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;


    self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                 delegate:self
                                            delegateQueue:nil];
}
ViewController.m方法

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@property (nonatomic, copy) void(^backgroundTransferCompletionHandler)();

@end
-(void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{

    self.backgroundTransferCompletionHandler = completionHandler;

}
- (void)viewDidLoad
{
    [super viewDidLoad];
    //Urls
    [self initializeFileDownloadDataArray];

    NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
    self.docDirectoryURL = [URLs objectAtIndex:0];

    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.GACDemo"];
    sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;


    self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                 delegate:self
                                            delegateQueue:nil];
}
NSUrlSession方法

-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
    AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;

    // Check if all download tasks have been finished.
    [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {

        if ([downloadTasks count] == 0) {
            if (appDelegate.backgroundTransferCompletionHandler != nil) {
                // Copy locally the completion handler.
                void(^completionHandler)() = appDelegate.backgroundTransferCompletionHandler;

                // Make nil the backgroundTransferCompletionHandler.
                appDelegate.backgroundTransferCompletionHandler = nil;

                [[NSOperationQueue mainQueue] addOperationWithBlock:^{
                    // Call the completion handler to tell the system that there are no other background transfers.
                    completionHandler();

                    // Show a local notification when all downloads are over.
                    UILocalNotification *localNotification = [[UILocalNotification alloc] init];
                    localNotification.alertBody = @"All files have been downloaded!";
                    [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
                }];
            }
        }
    }];
}
我可以一个接一个地下载所有文件,但在下载所有文件后,
urlsessiondifinisheventsforbackgroundurlsession
方法没有调用


仅下载所有文件后,我必须执行一些操作方法。

如果出现以下情况,则不会调用这些委托方法:

  • 任务完成时,应用程序已在运行

  • 该应用程序通过双击设备的home(主页)按钮并手动关闭而终止;或

  • 如果无法启动具有相同标识符的后台会话

  • 因此,显而易见的问题是:

    • 应用程序是如何终止的?如果没有终止,或者终止不正确(例如,您通过双击home按钮手动终止),将阻止调用这些委托方法

    • 您是否看到调用了
      handleEventsForBackgroundURLSession

    • 您是否在物理设备上执行此操作?这在模拟器上的行为不同

    总之,这里没有足够的信息来诊断精确的问题,但这些是委托方法可能无法被调用的常见原因

    你后来说,


    实际上,这是我第一次使用
    NSURLSession
    类。我的实际需求是,一旦下载(所有图像)完成,那么只有我可以从文档目录中检索图像,并且我可以在
    UICollectionView
    中显示


    我将遵循APPCODA提供的本教程。这里是链接

    如果这是您的要求,那么background
    NSURLSession
    可能有些过分。它比标准的NSURLSession慢,而且更复杂。只有在应用程序挂起/终止后确实需要大量下载才能在后台继续时,才使用后台会话

    您参考的那个教程似乎是对一个相当复杂的主题的简单介绍(尽管我不同意
    urlsessiondifinish…
    实现,如注释中所述)。我会这样做:

    - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session {
        // log message so we can see completion in device log; remove this once you're done testing the app
    
        NSLog(@"%s", __FUNCTION__);
    
        // Since you may be testing whether the terminated app is awaken when the
        // downloads are done, you might want to post local notification. 
        // (Otherwise, since you cannot use the debugger, you're just staring
        // at the device console hoping you see your log messages.) Local notifications
        // are very useful in testing this, so you can see when this method is 
        // called, even if the app wasn't running. Obviously, you have to register
        // for local notifications for this to work.
        //
        // UILocalNotification *notification = [[UILocalNotification alloc] init];
        // notification.fireDate = [NSDate date];
        // notification.alertBody = [NSString stringWithFormat:NSLocalizedString(@"Downloads done", nil. nil)];
        //
        // [[UIApplication sharedApplication] scheduleLocalNotification:notification];
    
        // finally, in `handleEventsForBackgroundURLSession` you presumably
        // captured the `completionHandler` (but did not call it). So this 
        // is where you'd call it on the main queue. I just have a property 
        // of this class in which I saved the completion handler.
    
        dispatch_async(dispatch_get_main_queue(), ^{
            if (self.savedCompletionHandler) {
                self.savedCompletionHandler();
                self.savedCompletionHandler = nil;
            }
        });
    }
    
    我脑海中的问题是,如果你只是为了收集视图下载图像,你是否真的需要后台会话。我只会这样做,如果有这么多的图像(或它们太大),它们无法合理下载,而应用程序仍在运行


    为了完整起见,我将在下面分享一个完整的后台下载演示:

    //  AppDelegate.m
    
    #import "AppDelegate.h"
    #import "SessionManager.h"
    
    @interface AppDelegate ()
    
    @end
    
    @implementation AppDelegate
    
    // other app delegate methods implemented here
    
    // handle background task, starting session and saving 
    // completion handler
    
    - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
        [SessionManager sharedSession].savedCompletionHandler = completionHandler;
    }
    
    @end
    

    正如苹果公司所说:


    如果iOS应用程序被系统终止并重新启动,则该应用程序可以使用相同的标识符创建新的配置对象和会话,并检索终止时正在进行的传输的状态。此行为仅适用于系统正常终止应用程序。如果用户从多任务屏幕终止应用程序,系统将取消会话的所有后台传输。此外,系统不会自动重新启动用户强制退出的应用程序。用户必须明确地重新启动应用程序,然后才能再次开始传输。

    作为旁白,我发现使用
    getTasksWithCompletionHandler
    很奇怪,因为
    urlsessiondifinishevents…
    仅在任务完成时调用。这对我来说似乎是多余的(尽管可能与你手头的问题无关)。如果这个场景发生,调用了
    handleEventsForBackgroundURLSession
    ,然后调用了
    UrlSessiondFinish…
    ,您就有了一个路径,在该路径中您没有调用
    completionHandler
    。我认为这条路径永远不会通过,但如果它通过了,您将引入一个新问题。实际上,这是我第一次使用NSUrlSession类。我的实际需求是,一旦下载(所有图像)完成,那么只有我可以从文档目录中检索图像,并且我可以在UICollectionVeiwI中显示我在APPCODA中遵循本教程。这是我浏览了该教程的链接,我认为它总体上是好的,尽管我不同意上面提到的
    urlsessiondifinisheventsforbackgroundurlsession
    实现。但我不认为这是你的问题。实际上这是我第一次使用NSUrlSession类。我的实际需求是,一旦下载(所有图像)完成,那么只有我可以从文档目录中检索图像,并可以在UICollectionVeiw中显示。我将遵循APPCODA提供的本教程。下面是appcoda.com/background-transfer-service-ios7的链接–@Rob该方法从未在模拟器(9.2)中被调用。但是我还没有在设备上测试。@RajanMaheshwari是的,我建议在设备上测试。在设备上,它确实会被调用。这非常有用!