2016-07-03 24 views
-1

Ich verwende Completion-Blöcke für jede meiner Funktionen (um zu vermeiden, eine while isDoingSomething-Schleife zu verwenden).Swift 2 OSX Wie verwende ich eine Schleife am Ende einer Reihe von Vervollständigungen, die eine Datenaufgabe enthält?

Ich bekomme das erwartete Array, wenn alle Blöcke abgeschlossen sind. Wenn ich jedoch versuche, dieses letzte Array zu durchlaufen, wird es wie erwartet fortlaufend durchlaufen, ohne jedoch die NSURLSessionDataTask in Request.sendRequest(..) für jede Iteration fortzusetzen.

ViewController.swift

import Cocoa 

class ViewController: NSViewController { 
    @IBOutlet weak var runButton: NSButton! 
    @IBOutlet weak var visitsTextField: NSTextField! 

    var accessToken = "" 
    var cookies = [NSHTTPCookie]() 
    var data = NSData?() 
    var userIds = [String]() 
    var usernames = [String]() 
    var contentsOfURL = NSString() 

    @IBAction func runButtonAction(sender: AnyObject) { 
     run({ 
      // if I remove the loop and visit only one profile, it completes OK 
      for username in self.usernames { 
       let profileVisitor = ProfileVisitor(profile: username) 
       profileVisitor.visit({ 

       }) 
      } 
     }) 
    } 

    func run(completion:() -> Void) { 
     let runManager = RunManager(desiredVisits: Int(visitsTextField.stringValue)!) 
     runManager.parseJSON({ 
      self.usernames = runManager.usernames 
      completion() 
     }) 
    } 
} 

RunManger.swift

import Cocoa 

class RunManager: NSObject { 
    var data = NSData?() 
    var desiredVisits = Int() 
    var usernames = [String]() 
    var userIds = [String]() 

    init(desiredVisits: Int) { 
     self.desiredVisits = desiredVisits 
    } 


    func parseJSON(completion:() -> Void) { 
     let jsonLimit = 40 
     var profileNames = [String]() 
     let finalVisits = desiredVisits % jsonLimit 
     let repeats = (desiredVisits/jsonLimit) + 1 
     let json: [String:NSObject] = [..., "limit":jsonLimit] 

     let url = "https://www.awebsite.com/1/path1/path2/path3" 
     let URL = NSURL(string: url)! 

     let vis = URLVisitor(URL: URL, params: "", method: "POST", jsonParams: json as! [String : NSObject]) 

     vis.execute({ 
      for i in 1..<repeats { 

       if vis.data != nil { 
        do { 
         let data = vis.data! 
         let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) 

         if let _usernames = json["data"] as? [[String: AnyObject]] { 
          for username in _usernames { 
           if let username = username["username"] as? String { 
            self.usernames.append(username) 
           } 
          } 
         } 
        } catch { 

        } 
       } 
      } 
      completion() 
     }) 
    } 
} 

URLVisitor

import Cocoa 

class URLVisitor: NSOperation { 
    var authorizationHeader = "" 
    var contentsOfURL = NSString() 
    var jsonParams = [String: NSObject]() 
    var isConnected = false 
    var method = String() 
    var params = String() 
    var statusCode = Int() 
    var cookies = [NSHTTPCookie]() 
    var URL: NSURL? 
    var isVisiting = false 
    var task = NSURLSessionDataTask() 
    var data = NSData?() 

    init(URL: NSURL, params: String, method: String, jsonParams: [String:NSObject]) { 
     self.URL = URL 
     self.params = params 
     self.method = method 
     self.jsonParams = jsonParams 
    } 

    func execute(completion:() -> Void) { 
     let request = Request(URL: URL!, params: params, method: method, jsonParams: jsonParams) 

     if !self.cookies.isEmpty { 
      request._setCookies(self.cookies) 
     } 

     request._setAuthorizationHeader(self.authorizationHeader) 
     request.sendRequest ({ 
      self.contentsOfURL = request.contentsOfURL 
      self.statusCode = request.getStatusCode() 
      self.data = request.data 
      completion() 
     }) 
    } 
} 

Anfrage

import Cocoa 

class Request: NSOperation { 
    var authorizationHeader = "" 
    var contentsOfURL = NSString() 
    var data: NSData? 
    var jsonParams = [String:NSObject]() 
    var isConnected = false 
    var method = String() 
    var params = String() 
    var statusCode = NSHTTPURLResponse().statusCode 
    var session = NSURLSession.sharedSession() 
    var url = String() 
    var URL = NSURL() 
    var cookies = [NSHTTPCookie]() 

    init(URL: NSURL, params: String, method: String, jsonParams: [String:NSObject]) { 
     self.jsonParams = jsonParams 
     self.method = method 
     self.params = params 
     self.URL = URL 
    } 

    func sendRequest(completion:() -> Void) { 
     let session = NSURLSession.sharedSession() 
     let request = NSMutableURLRequest(URL: URL) 
     request.HTTPMethod = method 

     if jsonParams.count != 0 { 
      do { 
       let jsonData = try NSJSONSerialization.dataWithJSONObject(jsonParams, options: .PrettyPrinted) 

       request.setValue("aplication/json; charset=utf-8", forHTTPHeaderField: "Content-Type") 
       request.HTTPBody = jsonData 
      } catch { 

      } 
     } else { 
      request.HTTPBody = self.params.dataUsingEncoding(NSUTF8StringEncoding) 
     } 

     let task = session.dataTaskWithRequest(request) { 
      (data, response, error) in 

      NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookies(self.cookies, forURL: self.URL, mainDocumentURL: nil) 
     if data != nil { 
      self.data = data! 
      print(data) 
      do { 
       swiftlet responseHeaders = response as! NSHTTPURLResponse 
       self.statusCode = responseHeaders.statusCode 

       switch self.statusCode { 
       case 200: 
        print("200: OK. getting contentsOfURL and cookies") 
        self.contentsOfURL = try NSString(contentsOfURL: self.URL, encoding: NSUTF8StringEncoding) 
        self.cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookiesForURL(self.URL)! 

        case 400: 
         print("400: page not found on web") 

        case 404: 
         print("404: page not found on server") 

        case 407: 
         print("407: failed authenticate proxy credentials") 

        default: 
         print("unable to get statusCode") 
        } 
       } catch { 

       } 
      } else { 
       print("\(self.statusCode): unable to get response ") 
      } 
      print("completing") 
      completion() // continue inside request call 
     } 
     task.resume() 
    } 

    func _setAuthorizationHeader(authorizationHeader: String) { 
     self.authorizationHeader = authorizationHeader 
    } 

    func _setCookies(cookies: [NSHTTPCookie]) { 
     self.cookies = cookies 
    } 

    func getStatusCode() -> Int { 
     return self.statusCode 
    } 

    func getContentsOfURL() -> NSString { 
     return self.contentsOfURL 
    } 
} 

Antwort

0

Ich endete mit einem Semaphor Versand und das hat den Trick gemacht.

func sendrequest() { lassen Semaphore = dispatch_semaphore_create (0)

let task = session.dataTaskWithRequest(request) { 
    // ... 
    dispatch_semaphore_signal(semaphore) 
} 
task.resume() 
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) 

}

1

Ich vermute, dass Sie nicht eine lokale Variable für Sitzung in der sendrequest Methode Ihrer Anfrage Klasse zu erklären gedachten.

let session = NSURLSession.sharedSession() 

Der lokale Session-Variable versteckt Ihre Klasse Sitzungsmitglied und wird so bald außerhalb des Gültigkeitsbereiches gehen, wie die Funktion beendet (was die gesamte Sitzung und Aufgabe es fällt).

[EDIT] Ich habe gerade bemerkt, dass Ihre lokale Variable die sharedSession verwendet, so dass die Aufgabe auch dann erhalten bleiben sollte, wenn sie außerhalb des Gültigkeitsbereichs liegt, da die Sitzung einen starken Verweis darauf haben soll (laut Dokumentation).

Das Problem muss etwas anderes sein.