

swiftにてiOSアプリの作成を始めた初心者です。十数年前にc言語でPCのソフトを趣味で作っていた程度の経験値になります。

現在、バックグラウンドで定期的（5分間隔程度）にwebAPIにアクセスして、情報の更新があれば通知を行うようなアプリを作りたいと思っています。

自分なりに調べたところ、以下のような印象を受けました。

  * バッテリーに負荷をかけないため、基本的にバックグラウンド処理は推奨されない
  * background fetchは処理の間隔をiOSが決める、かつ毎回一定では無いので5分程度の間隔で処理したい場合は向かない
  * Silent Push通知を利用して定期的にアプリを起こす？ただしPush通知実装にはサーバーの準備等、初心者には敷居がかなり高そう

時間を明確に指定してバックグラウンド処理を定期的に行うのは困難と考えた方が良いでしょうか？

ヒント等頂ければ幸いです。


CC BY-SA 3.0
2015-03-25T14:56:23.630
8392
2016-12-28T03:34:19.663
2016-12-28T03:34:19.663
76
9016
question
swift ios
バックグラウンドでの定期的な処理について


Objective-Cでの話ですが、  
タイマー(NSTimer)と位置情報を連携する方法があります。

位置情報の取得はバックグラウンドでも動作が可能なのですが、  
タイマーと連携させることで、  
5分ごとに何らかの処理を実行することができるようになります。

以前書いたブログの記事が参考になるかと思います。  
<http://grandbig.github.io/blog/2013/09/27/location-nstimer/>

位置情報を利用しない話だと思うので、  
リジェクトされる可能性はあるかもしれませんが、試してみてはいかがでしょうか？  
(Swiftにもタイマー処理はあるでしょうし。)

多少でも参考になれば幸いです。


CC BY-SA 3.0
2015-03-27T00:34:56.637
8457
2015-03-27T00:34:56.637
8968
8392
answer


background fetchでは間隔を制御できない＆最小間隔が長すぎるとのことでしたが、  
background fetchの一回の処理の中でsleepを利用する方法はいかがでしょうか？

具体的には、background fetchを有効にした上で、  
以下の様なコードをAppDelegateに実装します。  
（例はObjective-Cですが、Swiftでも同じことができるはずです）

[code]

    - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
    {
        while (YES) {
            NSLog(@"%s", __func__);
            //定期処理
    
            [NSThread sleepForTimeInterval:5*60];
        }
    }
    
[/code]

実際に利用するには、  
規約上問題のない実装なのか不明な点をクリアすることと、  
次回のbackground fetchが走った際に前回のループを中断させる等の制御が必要になると思います。

取り急ぎ作成したサンプルアプリをシミュレータで実行してみたところ、  
5分毎にNSLogで出力を行う処理を(初回を含めて)6回繰り返す  
という動作までは確認できました。


CC BY-SA 3.0
2015-03-27T07:04:29.040
8478
2015-03-27T08:14:03.193
2015-03-27T08:14:03.193
3227
3227
8392
answer


自己レスですが、以下のようなコードを見つけました。

[Swift how to use NSTimer background? - Stack
Overflow](https://stackoverflow.com/a/27895060)

[code]

    class ViewController: UIViewController {
        var backgroundTaskIdentifier: UIBackgroundTaskIdentifier?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            backgroundTaskIdentifier = UIApplication.sharedApplication().beginBackgroundTaskWithExpirationHandler({
                UIApplication.sharedApplication().endBackgroundTask(self.backgroundTaskIdentifier!)
            })
            var timer = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: "update", userInfo: nil, repeats: true)
        }
    
        func update() {
            println("Something cool")
        }
    }
    
[/code]

iOS simulator上で実行してみると、確かにバックグラウンドでもprintlnが実行され続けます。  
コメントとして”This apparently only runs for 3 minutes on iOS
7+.”との記載がありましたが、1時間経過後も動いたままでした。

不思議に思い、別途BackgroundFetchのperformFetchWithCompletionHandler中に同様にNSTimerを埋め込んでみたのですが、こちらも同様にバックグラウンドで処理が継続し続けます。

これもAppleにリジェクトされてしまうのかもしれませんが、長時間処理が許されていないはずの処理の中にNSTimerを埋め込んで一度呼ばれてしまいさえすれば、バックグラウンドでも処理が継続されてしまうのは少し不思議です。これが単純にiOS
simulator上だからであって、実機では動かないのであれば納得なのですが・・・。

これらについて私の勘違いについての指摘やご知見ある方いればコメント頂ければ幸いです。


CC BY-SA 3.0
2015-03-28T14:53:09.660
8513
2016-12-27T23:13:06.400
2017-05-23T12:38:55.307
-1
9016
8392
answer


上記のバックグラウンドタスクとタイマーの方法を実機で試してみましたが、やはり3分程度でバックグラウンド処理が止まってしまいました。

Xcodeでデバッグしている間は、少なくとも3分以上は動いていました。


CC BY-SA 3.0
2015-09-26T03:08:53.797
16937
2015-09-26T03:08:53.797
12454
8392
answer