2017-08-17 12 views
1

私は自分のアプリケーションの解析クラスを構築したいと思います。シングルトンを使用しています。素早くシングルトンで非同期関数を呼び出す適切な方法

これを実行すると、最初にopenSession()を実行するのではなく、tagEvent関数がすぐに実行されるため、sessionIdはnilを返します。 このようなクラスを適切な初期化で作成し、シングルトンインスタンスのようにアプリケーションを幅広く使用するにはどうすればよいですか。

Analytics.swift

final class Analytics { 
    public static let instance = Analytics() 
    private var baseUrl = "http://localhost" 
    public var deviceId: String? 

    private init(){ 
     self.deviceId = SomeFunctionGetsDeviceID() 
    } 

    func openSession(){ 
     // make an API call to create a session and save sessionId to UserDefaults 
     if let url = URL(string: self.baseUrl + "/session"){ 
      let params:[String:Any] = ["deviceId": "\(self.deviceId!)"] 

      var request = URLRequest(url: url) 
      request.setValue("application/json", forHTTPHeaderField:"Content-Type") 
      request.httpMethod = "POST" 
      request.httpBody = try! JSONSerialization.data(withJSONObject: params, options: []) 

      AnalyticsSessionManager.sharedManager.request(request as URLRequestConvertible).validate().responseObject(completionHandler: { (response: DataResponse<SessionOpenResponse>) in 
       if response.result.value != nil { 
        UserDefaults.standard.set(response.result.value?.sessionId, forKey: "sessionId") 
       } 
      }) 
     } 
    } 

    func closeSession(){ 
     // make an API call to close a session and delete sessionId from UserDefaults 
    ... 
    } 

    func tagEvent(eventName: String, attributes: [String : String]? = nil) { 
     if let url = URL(string: self.baseUrl + "/event"), 
      let sessionId = UserDefaults.standard.string(forKey: "sessionId"){ 
      ... 
      // make an API call to create an event with that sessionId 
     } 
    } 
} 

AppDelegate.swift

func application(_ application: UIApplication, 
    didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 
    Analytics.instance.openSession() 
    Analytics.instance.tagEvent(eventName: "App Launch", attributes: 
    ["userID":"1234"]) 
} 
+0

と呼ばれています。おそらく問題は、非同期呼び出しを行うため、 'openSession'がすぐに返ることです。 – rmaddy

+0

"API呼び出しを行う"とはどういうものですか? –

+0

私はAPI呼び出しの部分を作成しました。@rmaddy – invincible

答えて

1

私の最高の推測ではのOpenSession関数は非同期で仕事をしていると非同期コードを持って前にtagEventコールが入ってきています完了しました。これにはいくつかの方法があります:

1)タグイベントコードがopenSession呼び出しが完了するのを待つように同期を追加します(進行中の場合)。進行中でない場合は、おそらくそれが自動的に完了するのを待って、のOpenSessionを呼び出す必要があり、その機能に

2のコードを実行)のOpenSessionから完了ハンドラを追加し、その筐体の内部で次のようなtagEventを呼び出すことができます。

func openSession(completionHandler: @escapaing (Bool) ->()){ 
    // make an API call to create a session and save sessionId to UserDefaults 
    ... 
    UserDefaults.standard.set(someSessionID, forKey: "sessionId") 

    // when done with async work 
    completionHandler(true) 
} 
そして、アプリのデリゲートで

Analytics.instance.openSession() { (success) 
    Analytics.instance.tagEvent(eventName: "App Launch", attributes:["userID":"1234"]) 
} 

3)*これは私がのOpenSessionへの呼び出しは、クラスの外で必要とされることはないだろう*それを修正するような方法です。 、のOpenSession関数で

private var initialized = false 

すべてがtagEvent機能で

initialized = true 

を完了した後にこれを設定します:私は解析クラスにフラグを追加します

func tagEvent(eventName: String, attributes: [String : String]? = nil) { 
    // Check for initialization 
    if (!initialized) { 
     openSession() { (success) in 
      // perform your tagEvent code 
     }) 
    } else { 
     if let url = URL(string: self.baseUrl + "/event"), 
      let sessionId = UserDefaults.standard.string(forKey: "sessionId"){ 
      ... 
      // make an API call to create an event with that sessionId 
     } 
    } 
} 
+0

@rmaddyは絶対に正しいです。これは、シングルトンの問題ではなく、非同期の問題です。 – Shawn

+0

答えをありがとう。しかし、私はAppDelegateでopenSessionを一度呼びたいと思っていました。あなたのケースでは、イベントにタグを付けるたびにセッションを開くのではないでしょうか? – invincible

+0

追加した3番目のオプションを確認してください。コードを合理化することができますが、うまくいけば、これは一般的な考え方を表しています。 – Shawn

0

あなたが実装することができます以下のように、アナリティクスクラスへの静的な参照を提供するための「内部」クラス(注:finalキーワードを削除):

他のクラスでアナリティクスクラスから
class Analytics { 

// properties ... 

    class var sharedInstance: Analytics { 
     struct Static { 
      static let instance: Analytics = Analytics() 
     } 
     return Static.instance 
    } 

// other methods (init(), openSession(), closeSession(), tagEvent()) 

} 

次の呼び出し方法、次のように: `openSession`は間違いtagEvent``前

Analytics.sharedInstance.openSession() 
Analytics.sharedInstance.closeSession() 
Analytics.sharedInstance.tagEvent(...) 
+0

答えをありがとうが、同じ方法で結果が出るが、tagEvent関数はセッションを作成するための非同期API呼び出しを行っているopenSession関数を待つことなく実行される – invincible

関連する問題