2017-03-10 2 views
0

Ich versuche, ein UILabel mit einer Zeichenfolge aus einer REST-API mit JSON anzuzeigen, hatte aber kein Glück. Ich kann die Zeichenfolge in der Konsole problemlos drucken, aber wenn Sie versuchen, diese Zeichenfolge mit einem UILabel anzuzeigen, wird es leer angezeigt.UILabel kann nicht mit JSON-Daten aktualisiert werden

Dies ist der Testcode mit denen ich arbeite:

import UIKit 

class List { 
    var title = String() 
} 

class ViewController: UIViewController { 
    override func viewDidLoad() { 
    super.viewDidLoad() 
    let list = List() 
    callAPI() 
    let width = view.bounds.width 
    let height = view.bounds.height 
    let label: UILabel = { 
     let label = UILabel(frame: CGRect(x: 0, y: height/2 - 50, width: width, height: 50)) 
     label.backgroundColor = UIColor.red 
     label.text = title 
    return label 
    }() 
    view.addSubview(label) 
    print("Label Text: \(list.title)") 
    } 
} 

let url = URL(string: "https://jsonplaceholder.typicode.com/todos/") 

func callAPI() { 
    URLSession.shared.dataTask(with: url!, completionHandler: { 
    (data, response, error) in 
    if error != nil { 
     print(error!) 
     return 
    } 
    do { 
     let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSMutableArray 
     let array = json[0] as! [String:Any] 
     let title = array["title"] as! String 
     print("Title: \(title)") 
     let list = List() 
     list.title = title 
    } 
    catch let jsonError { 
     print(jsonError) 
    } 
    }).resume() 
} 
+0

Wie nutzen Sie Ihre 'List' Klasse und die' list' Eigenschaft? – rmaddy

+0

Der Code 'label.text = title' wird sofort ausgeführt, bevor der Aufruf der API beginnt.Sie können den Titel nur von JSON erwarten, während oder nachdem der Beendigungshandler ausgeführt wurde. Deshalb sollten Sie einen rmaddy-Hinweis nehmen und die Benutzeroberfläche in diesem Handler aktualisieren. – danh

Antwort

0

Es scheint, diese Zeilen ersetzen:

let list = List() 
list.title = title 

mit: Sie

label.text = title 

Der Code erstellt, aktualisiert und verwirft eine List Instanz, unternimmt jedoch keinen Versuch, Ihre aktuellezu aktualisieren.

Sie müssen den Anruf auch auf callAPI() verschieben, nachdem Sie das Etikett erstellt und eingerichtet haben.

+0

Welche "list list = List()" beziehen Sie sich? – sMk

+0

Sie haben diese beiden Codezeilen nur an einer Stelle, direkt nach dem Parsen der JSON-Daten. – rmaddy

+0

ok, aber jetzt bekomme ich diesen Fehler ... "Verwendung des nicht aufgelösten Bezeichners" label " – sMk

0

In Ihrem Viewcontroller, haben Sie eine Instanz von List(), erstellt aber callAPI() schafft eine eigene Instanz von List() und Updates, die Titel-Eigenschaft statt der Titel Eigenschaft der Instanz in Ihrem Viewcontroller.

können Sie entweder entfernen Sie die callAPI() Methode, den Code direkt in Ihre Viewcontroller setzen und label.text direkt aktualisieren Sie callAPI akzeptieren einen Parameter vom Typ UILabel und aktualisieren Sie es gerne haben:

class ViewController: UIViewController { 
    override func viewDidLoad() { 
     super.viewDidLoad() 


     let width = view.bounds.width 
     let height = view.bounds.height 

     let label: UILabel = { 
      let label = UILabel(frame: CGRect(x: 0, y: height/2 - 50, width: width, height: 50)) 
      label.backgroundColor = UIColor.red 
      return label 
     } 

     callAPI(label) 

     view.addSubview(label) 
     print("Label Text: \(list.title)") 
    } 
} 

let url = URL(string: "https://jsonplaceholder.typicode.com/todos/") 

func callAPI(_ label: UILabel) { 
    URLSession.shared.dataTask(with: url!, completionHandler: { 
    (data, response, error) in 
    if error != nil { 
     print(error!) 
     return 
    } 
    do { 
     let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSMutableArray 
     let array = json[0] as! [String:Any] 
     let title = array["title"] as! String 
     print("Title: \(title)") 

     label.text = title 
    } 
    catch let jsonError { 
     print(jsonError) 
    } 
    }).resume() 
} 

, oder Sie können haben callAPI eine Instanz von List() als Parameter übernehmen und aktualisieren Sie die title Eigenschaft:

class ViewController: UIViewController { 
    override func viewDidLoad() { 
     super.viewDidLoad() 

     let list = List() 
     callAPI(list) 

     let width = view.bounds.width 
     let height = view.bounds.height 

     let label: UILabel = { 
      let label = UILabel(frame: CGRect(x: 0, y: height/2 - 50, width: width, height: 50)) 
      label.backgroundColor = UIColor.red 
      label.text = list.title 
      return label 
     } 

     view.addSubview(label) 
     print("Label Text: \(list.title)") 
    } 
} 

let url = URL(string: "https://jsonplaceholder.typicode.com/todos/") 

func callAPI(_ list: List) { 
    URLSession.shared.dataTask(with: url!, completionHandler: { 
    (data, response, error) in 
    if error != nil { 
     print(error!) 
     return 
    } 
    do { 
     let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSMutableArray 
     let array = json[0] as! [String:Any] 
     let title = array["title"] as! String 
     print("Title: \(title)") 

     list.title = title 
    } 
    catch let jsonError { 
     print(jsonError) 
    } 
    }).resume() 
} 
0

Warum Verwenden Sie keine closure in Ihrer asynchronen Netzwerkfunktion?

Was mit Ihrem Code passiert, ist, dass Sie Ihren Netzwerkanruf versenden (was einige Zeit in Anspruch nimmt). Während der Netzwerkanruf verarbeitet wird, wird der Code weiterhin ausgeführt. Das bedeutet, dass Ihre Leitung label.text = title angerufen wird, bevor der Netzwerkanruf beendet wird. An einem bestimmten Punkt wird der Netzwerkanruf abgeschlossen und der Code zum Erstellen der Liste ausgeführt. Der Etikettentext ist jedoch seit langem (in Bezug auf Computer) festgelegt worden.

Mithilfe eines Abschlusselements können Sie angeben, dass der Code ausgeführt werden soll, nachdem JSON abgerufen, serialisiert und in ein List-Objekt umgewandelt wurde.

Der folgende Code fügt Ihrer callAPI-Funktion einen Abschlussparameter hinzu. Wie jeder andere Parameter hat auch dieser Parameter den Namen completion. Nachdem der Netzwerkaufruf ausgeführt wurde, rufen Sie diesen Parameter auf und welcher Code übergeben wird, wird an diesem Punkt ausgeführt.

class ViewController: UIViewController { 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     callAPI { (list) in 
      let width = self.view.bounds.width 
      let height = self.view.bounds.height 
      let label = UILabel(frame: CGRect(x: 0, y: height/2 - 50, width: width, height: 50)) 
      label.backgroundColor = UIColor.red 
      label.text = list.title 
      DispatchQueue.main.async(execute: { 
       self.view.addSubview(label) 
      }) 
      print("Label Text: \(list.title)") 
     } 
    } 

    let url = URL(string: "https://jsonplaceholder.typicode.com/todos/") 

    func callAPI(completion: @escaping (_ list: List) -> Void) { 
     URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) in 
      if error != nil { 
       print(error!) 
       return 
      } 
      do { 
       let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSMutableArray 
       let array = json[0] as! [String:Any] 
       let title = array["title"] as! String 
       print("Title: \(title)") 
       let list = List() 
       list.title = title 

       completion(list) 
      } 
      catch let jsonError { 
       print(jsonError) 
      } 
     }).resume() 
    } 
} 
0

Versuchen Sie diesen einen Code.

import UIKit 

class List { 
    var title = String() 
} 

class ViewController: UIViewController { 
    var list = List() 

let url = URL(string: "https://jsonplaceholder.typicode.com/todos/") 
override func viewDidLoad() { 
    super.viewDidLoad() 
    callAPI() 

} 

func setLable() { 
    let width = view.bounds.width 
    let height = view.bounds.height 
    let label: UILabel = { 
     let label = UILabel(frame: CGRect(x: 0, y: height/2 - 50, width: width, height: 50)) 
     label.backgroundColor = UIColor.red 
     label.text = list.title 
     return label 
    }() 
    self.view.addSubview(label) 
    print("Label Text: \(list.title)") 
} 


func callAPI() { 
    URLSession.shared.dataTask(with: url!, completionHandler: { 
     (data, response, error) in 
     if error != nil { 
      print(error!) 
      return 
     } 
     do { 
      let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! NSMutableArray 
      let array = json[0] as! [String:Any] 
      let title = array["title"] as! String 
      print("Title: \(title)") 
      self.list.title = title 
      self.setLable() 
     } 
     catch let jsonError { 
      print(jsonError) 
     } 
    }).resume() 
    } 
} 
Verwandte Themen