JSON Paktet decoden

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • JSON Paktet decoden

    Hallo,

    aktuell beschäftige ich mich damit folgendes JSON Paket zu decoden:

    Quellcode

    1. {"status":"ok","time":1530563992,"data":[{"question_info":{"id":"1","title":"Ja Moin","pictures":["GahNiem0","iePh5che","Ooroo7oo","up6pho4A"],"date":"1530094596"},"user_info":{"id":"29","username":"pascalpru","profilepicture":"upload2\/profilbild_user29.jpg"}},{"question_info":{"id":"2","title":"Was geht","pictures":["Oodei3pu","ohreiTe5","reec2Bai"],"date":"1530094734"},"user_info":{"id":"32","username":"JoELCHAPO","profilepicture":"upload2\/profilbild_user32.png"}},{"question_info":{"id":"3","title":"Valence ist cool","pictures":["Ohbii3mu","thae0Eej"],"date":"1530094877"},"user_info":{"id":"34","username":"MaxMusti","profilepicture":"upload2\/profilbild_user34.png"}},{"question_info":{"id":"4","title":"Coole Schuhe","pictures":["Taebui9N","saeSh6ip","up6pho4A"],"date":"1530094887"},"user_info":{"id":"35","username":"philpru98","profilepicture":"upload2\/profilbild_user35.png"}},{"question_info":{"id":"5","title":"Welcher Schrank?","pictures":["Ejohjuo8","eiHeePh7","naiza3Fe","Woh0yoof"],"date":"1530094897"},"user_info":{"id":"36","username":"Test","profilepicture":""}},{"question_info":{"id":"6","title":"Wo soll ich hin gehen?","pictures":["tae9Daet","Aenie3oh"],"date":"1530094907"},"user_info":{"id":"37","username":"Sonja","profilepicture":""}},{"question_info":{"id":"7","title":"Welchen Urlaub?","pictures":["pheWohs6","eiph1Eeg"],"date":"1530095252"},"user_info":{"id":"38","username":"Kalle","profilepicture":""}},{"question_info":{"id":"8","title":"Handy?","pictures":["oom0Nu0n","xee7Thah","ak0EeP1U"],"date":"1530095262"},"user_info":{"id":"39","username":"Manny","profilepicture":""}},{"question_info":{"id":"9","title":"Was ist geiler?","pictures":["uQu0aigh","ienej3Wi","FahH2ohv","yohThie1","ahKai2Ro"],"date":"1530095360"},"user_info":{"id":"40","username":"Tobi","profilepicture":""}},{"question_info":{"id":"10","title":"Was soll ich essen?","pictures":["Cexom0ii","ix8IkeiR","Quughu2i","ulaeCoR7"],"date":"1530095367"},"user_info":{"id":"41","username":"derced","profilepicture":null}}]}


    Jetzt mal abgesehen davon das ich das Paket sicherlich noch kompakter verschicken könnte und aufbessern könnte habe gibt es ein paar Dinge bei denen ich eure Hilfe brauch. Ich schaffe es nämlich an sämtliche Daten aus diesem Paket ran zu kommen und die Daten in Variablen zu speichern. Nur leider sieht das alles nicht sonderlich schön aus und ich würde meinen Code den ihr im folgenden seht gerne aufgeräumter haben. Aber jetzt erstmal der Code:


    Quellcode

    1. import UIKit
    2. import PlaygroundSupport
    3. PlaygroundPage.current.needsIndefiniteExecution = true
    4. struct StepOne: Codable {
    5. var data: [StepTwo]?
    6. }
    7. struct StepTwo: Codable {
    8. var question_info: StepThree?
    9. var user_info: StepFour?
    10. }
    11. struct StepThree: Codable {
    12. var title: String
    13. var id: String
    14. enum CodingKeys: String, CodingKey {
    15. case title
    16. case id
    17. }
    18. init(from decoder: Decoder) throws {
    19. let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
    20. self.title = try valueContainer.decode(String.self, forKey: CodingKeys.title)
    21. self.id = try valueContainer.decode(String.self, forKey: CodingKeys.id)
    22. print("User mit der ID \(id), sagt \(title)")
    23. }
    24. }
    25. struct StepFour: Codable {
    26. var username: String
    27. enum CodingKeys: String, CodingKey {
    28. case username
    29. }
    30. init(from decoder: Decoder) throws {
    31. let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
    32. self.username = try valueContainer.decode(String.self, forKey: CodingKeys.username)
    33. print("\(username) ")
    34. }
    35. }
    36. extension URL {
    37. func withQueries(_ queries: [String: String]) -> URL? {
    38. var components = URLComponents(url: self, resolvingAgainstBaseURL: true)
    39. components?.queryItems = queries.compactMap{ URLQueryItem(name: $0.0, value: $0.1) }
    40. return components?.url
    41. }
    42. }
    43. let baseURL = URL(string: "http://192.168.178.94/v0.1/questions.php")!
    44. let query: [String: String] = [
    45. "api_key": "DEMO_KEY",
    46. ]
    47. let url = baseURL.withQueries(query)!
    48. let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
    49. let decoder = JSONDecoder()
    50. if let data = data,
    51. let dictionary = try? decoder.decode(StepOne.self, from: data) {
    52. print(dictionary)
    53. }
    54. }
    55. task.resume()
    Alles anzeigen
    Ihr seht ja in dem structure StepTwo das ich mit question_info und user_info zwei weitere unterschiedliche Structures anspreche um an die Daten zu kommen. Die beiden Variablen question_info und user_info sind zwei Arrays die in dem JASON-Paket enthalten sind. Es wäre sehr schön wenn es irgendwie gehen würde das ich mir das structure StepFour schenken könnte und alle meine Daten aus BEIDEN ARRAYS aus StepThree bekommen könnte. Aktuell kriege ich das aber leider nicht anders hin.

    Außerdem habe ich das Problem das ich in der Konsole zusätzlich zu dem was ich auslesen möchte und was auch klappt, das hier mit angezeigt wird:

    Quellcode

    1. StepOne(data: Optional([__lldb_expr_127.StepTwo(question_info: Optional(__lldb_expr_127.StepThree(title: "Ja Moin", id: "1")), user_info: Optional(__lldb_expr_127.StepFour(username: "pascalpru"))), __lldb_expr_127.StepTwo(question_info: Optional(__lldb_expr_127.StepThree(title: "Was geht", id: "2")), user_info: Optional(__lldb_expr_127.StepFour(username: "JoELCHAPO"))), __lldb_expr_127.StepTwo(question_info: Optional(__lldb_expr_127.StepThree(title: "Valence ist cool", id: "3")), user_info: Optional(__lldb_expr_127.StepFour(username: "MaxMusti"))), __lldb_expr_127.StepTwo(question_info: Optional(__lldb_expr_127.StepThree(title: "Coole Schuhe", id: "4")), user_info: Optional(__lldb_expr_127.StepFour(username: "philpru98"))), __lldb_expr_127.StepTwo(question_info: Optional(__lldb_expr_127.StepThree(title: "Welcher Schrank?", id: "5")), user_info: Optional(__lldb_expr_127.StepFour(username: "Test"))), __lldb_expr_127.StepTwo(question_info: Optional(__lldb_expr_127.StepThree(title: "Wo soll ich hin gehen?", id: "6")), user_info: Optional(__lldb_expr_127.StepFour(username: "Sonja"))), __lldb_expr_127.StepTwo(question_info: Optional(__lldb_expr_127.StepThree(title: "Welchen Urlaub?", id: "7")), user_info: Optional(__lldb_expr_127.StepFour(username: "Kalle"))), __lldb_expr_127.StepTwo(question_info: Optional(__lldb_expr_127.StepThree(title: "Handy?", id: "8")), user_info: Optional(__lldb_expr_127.StepFour(username: "Manny"))), __lldb_expr_127.StepTwo(question_info: Optional(__lldb_expr_127.StepThree(title: "Was ist geiler?", id: "9")), user_info: Optional(__lldb_expr_127.StepFour(username: "Tobi"))), __lldb_expr_127.StepTwo(question_info: Optional(__lldb_expr_127.StepThree(title: "Was soll ich essen?", id: "10")), user_info: Optional(__lldb_expr_127.StepFour(username: "derced")))]))
    Gibt es ne Möglichkeit diese Konsolen Ausgabe zu verhindern ?
  • So, das ganze erstmal etwas nachvollziehbarer nachgebaut. Denkt denn niemand an die Kinder! ;(
    Ich denke mal, damit können die anderen hier auch etwas besser ihren Senf dazugeben.

    Quellcode

    1. import Foundation
    2. let jsonString =
    3. """
    4. {"status":"ok","time":1530563992,"data":[{"question_info":{"id":"1","title":"Ja Moin","pictures":["GahNiem0","iePh5che","Ooroo7oo","up6pho4A"],"date":"1530094596"},"user_info":{"id":"29","username":"pascalpru","profilepicture":"upload2/profilbild_user29.jpg"}},{"question_info":{"id":"2","title":"Was geht","pictures":["Oodei3pu","ohreiTe5","reec2Bai"],"date":"1530094734"},"user_info":{"id":"32","username":"JoELCHAPO","profilepicture":"upload2/profilbild_user32.png"}},{"question_info":{"id":"3","title":"Valence ist cool","pictures":["Ohbii3mu","thae0Eej"],"date":"1530094877"},"user_info":{"id":"34","username":"MaxMusti","profilepicture":"upload2/profilbild_user34.png"}},{"question_info":{"id":"4","title":"Coole Schuhe","pictures":["Taebui9N","saeSh6ip","up6pho4A"],"date":"1530094887"},"user_info":{"id":"35","username":"philpru98","profilepicture":"upload2/profilbild_user35.png"}},{"question_info":{"id":"5","title":"Welcher Schrank?","pictures":["Ejohjuo8","eiHeePh7","naiza3Fe","Woh0yoof"],"date":"1530094897"},"user_info":{"id":"36","username":"Test","profilepicture":""}},{"question_info":{"id":"6","title":"Wo soll ich hin gehen?","pictures":["tae9Daet","Aenie3oh"],"date":"1530094907"},"user_info":{"id":"37","username":"Sonja","profilepicture":""}},{"question_info":{"id":"7","title":"Welchen Urlaub?","pictures":["pheWohs6","eiph1Eeg"],"date":"1530095252"},"user_info":{"id":"38","username":"Kalle","profilepicture":""}},{"question_info":{"id":"8","title":"Handy?","pictures":["oom0Nu0n","xee7Thah","ak0EeP1U"],"date":"1530095262"},"user_info":{"id":"39","username":"Manny","profilepicture":""}},{"question_info":{"id":"9","title":"Was ist geiler?","pictures":["uQu0aigh","ienej3Wi","FahH2ohv","yohThie1","ahKai2Ro"],"date":"1530095360"},"user_info":{"id":"40","username":"Tobi","profilepicture":""}},{"question_info":{"id":"10","title":"Was soll ich essen?","pictures":["Cexom0ii","ix8IkeiR","Quughu2i","ulaeCoR7"],"date":"1530095367"},"user_info":{"id":"41","username":"derced","profilepicture":null}}]}
    5. """
    6. let jsonData = jsonString.data(using: .utf8)!
    7. // The data structures
    8. struct RootElement: Codable {
    9. let status: String
    10. let time: Int
    11. let data: [UserQuestionElement]
    12. }
    13. struct UserQuestionElement: Codable {
    14. let question_info: QuestionInfo
    15. let user_info: UserInfo
    16. }
    17. struct QuestionInfo: Codable {
    18. let id: String
    19. let title: String
    20. let pictures: [String]
    21. let date: String
    22. }
    23. struct UserInfo: Codable {
    24. let id: String
    25. let username: String
    26. let profilepicture: String?
    27. }
    28. // custom printout
    29. extension RootElement: CustomStringConvertible {
    30. var description: String {
    31. var str = "[\n"
    32. for d in data { str += "\(d);\n" }
    33. return str + "]"
    34. }
    35. }
    36. extension UserQuestionElement: CustomStringConvertible {
    37. var description: String {
    38. return "\t question: (\(question_info))\n\t user: (\(user_info))"
    39. }
    40. }
    41. extension QuestionInfo: CustomStringConvertible {
    42. var description: String {
    43. return "title: \(title) pictures: \(pictures)"
    44. }
    45. }
    46. extension UserInfo: CustomStringConvertible {
    47. var description: String {
    48. return "username: \(username) profilepicture: \(profilepicture ?? "")"
    49. }
    50. }
    51. let decoder = JSONDecoder()
    52. let root = try? decoder.decode(RootElement.self, from: jsonData)
    53. print(root!)
    Alles anzeigen
    Alles, was Du darüber hinaus mit CodingKeys und sonstigen Coding-Feinheiten einbaust, ist schlichtweg nur eine Frage, des Verhältnisses Deines Datenmodells zur JSON-Repräsentation. Wenn Dir beides 'gehört', kannst Du Deinen Aufwand auf ein bares Minimum (siehe oben) beschränken.

    Mit Verlaub: Du bist da notorisch diffus. Was ist gegeben, was willst Du erreichen? Das sind die Fragen. Nicht "Ich würde da gerne ohne Plan aufräumen".

    ThisIsBeat schrieb:

    Gibt es ne Möglichkeit diese Konsolen Ausgabe zu verhindern ?
    Ja klar! Mach einfach keinen print() darauf! :D

    Nur zum Verständnis. 'Programme' eines Playgrounds laufen im Debugger. Dieses __lldb_expr_127.StepThree ist leider etwas technisch. 'lldb' steht da für Low Level DeBugger… Die Standard-Ausgabe in Playgrounds war früher mal etwas weniger technisch.

    Wenn Du solche print-Ausgaben selber kontrollieren und gestalten willst, dann müssen Deine Typen CustomStringConvertible implementieren. Siehe oben.

    Nach obigen Code sieht das dann wie folgt aus:

    Quellcode

    1. [
    2. question: (title: Ja Moin pictures: ["GahNiem0", "iePh5che", "Ooroo7oo", "up6pho4A"])
    3. user: (username: pascalpru profilepicture: upload2/profilbild_user29.jpg);
    4. question: (title: Was geht pictures: ["Oodei3pu", "ohreiTe5", "reec2Bai"])
    5. user: (username: JoELCHAPO profilepicture: upload2/profilbild_user32.png);
    6. question: (title: Valence ist cool pictures: ["Ohbii3mu", "thae0Eej"])
    7. user: (username: MaxMusti profilepicture: upload2/profilbild_user34.png);
    8. question: (title: Coole Schuhe pictures: ["Taebui9N", "saeSh6ip", "up6pho4A"])
    9. user: (username: philpru98 profilepicture: upload2/profilbild_user35.png);
    10. question: (title: Welcher Schrank? pictures: ["Ejohjuo8", "eiHeePh7", "naiza3Fe", "Woh0yoof"])
    11. user: (username: Test profilepicture: );
    12. question: (title: Wo soll ich hin gehen? pictures: ["tae9Daet", "Aenie3oh"])
    13. user: (username: Sonja profilepicture: );
    14. question: (title: Welchen Urlaub? pictures: ["pheWohs6", "eiph1Eeg"])
    15. user: (username: Kalle profilepicture: );
    16. question: (title: Handy? pictures: ["oom0Nu0n", "xee7Thah", "ak0EeP1U"])
    17. user: (username: Manny profilepicture: );
    18. question: (title: Was ist geiler? pictures: ["uQu0aigh", "ienej3Wi", "FahH2ohv", "yohThie1", "ahKai2Ro"])
    19. user: (username: Tobi profilepicture: );
    20. question: (title: Was soll ich essen? pictures: ["Cexom0ii", "ix8IkeiR", "Quughu2i", "ulaeCoR7"])
    21. user: (username: derced profilepicture: );
    22. ]
    Alles anzeigen
    Das iPhone sagt: "Zum Antworten streichen". Wie? Echt Jetzt? Muß ich erst die Wohnung streichen!?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von torquato ()

  • @torquato okay super das hat schon mal alles geholfen, vielen Dank für deine Mühe. Mein Code schaut direkt besser aus :) Eine Frage hätte ich da aber noch. Wie kann ich auf Variablen der Structures UserInfo und QuestionInfo außerhalb der Struktures zugreifen ?

    Ich meine im wesentlichen mache ich das ja schon mit dem Code, nur für RootElement:

    Quellcode

    1. let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
    2. let decoder = JSONDecoder()
    3. if let data = data,
    4. let dictionary = try? decoder.decode(RootElement.self, from: data) {
    5. print(dictionary)
    6. }
    7. }


    Doch ich denke beispielsweise an den Fall das ich einem Label in meinem ViewController "username" zuordnen möchte, nur leider komme ich über die mir bekannten Wege gerade gar nicht an die Variable ran in der dann alle Werte aus dem JSON Paket gespeichert sind...


    So komme ich zum Beispiel nicht dran:


    Quellcode

    1. let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
    2. let decoder = JSONDecoder()
    3. if let data = data,
    4. let dictionary = try? decoder.decode(UserInfo.self, from: data) {
    5. print(dictionary.username)
    6. }
    7. }
    Ich hoffe es wird klar was ich meine und vorhabe :)
  • In dem RootElement befindet sich ja ein data Array mit den UserQuestionElements. Darin gibt es dann question_info und user_info.

    Wenn Du ein spezielles user_info haben möchtest, dann musst Du das data Array danach durchsuchen. Ich tippe mal, dass es in Swift auch etwas wie Predicate gibt.
  • torquato schrieb:

    Sa mußt Du Dich dann halt entsprechend durch Deine verschachtelten Strukturen durchhangeln. Z.B.:

    Quellcode

    1. let username = root?.data[0].user_info.username
    2. print(username)
    Okay also das hat schon mal weiter geholfen. Doch leider kriege ich das nur wie folgt hin:

    Quellcode

    1. let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
    2. let decoder = JSONDecoder()
    3. if let data = data,
    4. let dictionary = try? decoder.decode(RootElement.self, from: data) {
    5. print(dictionary)
    6. let username = dictionary.data![0].user_info?.username
    7. print(username!)
    8. }
    9. }
    Das Problem ist das ich nur innerhalb von task darauf zugreifen kann. Ich habe beispielsweise eine TableView und die Zuordnung der Werte bisher immer so gelöst:

    Quellcode

    1. let cell = tableView.dequeueReusableCell(withIdentifier: "QuestionLine", for: indexPath) as! UserTableViewCell
    2. let user = users[indexPath.row]
    3. cell.titleLabel.text = user.question
    4. cell.detailLabel.text = user.name
    5. let image = UIImage(named: user.profilePicture)
    6. cell.imageV.image = image
    Die Daten habe ich dabei aus dem Array gezogen:

    Quellcode

    1. var users: [User] = [
    2. User(userID: 1, profilePicture: "bild_user29Lifestyle" ,name: "Max Mustermann", question: "Was findet ihr am besten ?"),
    3. User(userID: 2, profilePicture: "bild_user29Lifestyle1", name: "Joel Ertico", question: "Links oder Rechts ?"),
    4. User(userID: 3, profilePicture: "bild_user29Lifestyle2-1", name: "Travis Scott", question: "Welches Cover ?")
    5. ]

    Mir ist irgendwie nicht ersichtlich wie ich diese Zuordnung vornehmen kann wenn ich auf die Daten im JSON-Paket nicht auch von außerhalb zugreifen kann, zumal ich bei der Variante oben auch noch den Index mit angeben muss :/
  • Das hängt insgesamt davon ab, wie Du Dein Datenmodell gestalten willst…
    Du kannst dieses data-Array, das Du in der Closure ausliest, ja auch als Property Deines Controllers speichern… Das hängt eben vom Datenmodell ab und wie das alles zusammenhängen soll. Ohne das Gesamtbild, kann man Dir da schlecht den passenden Rat geben…

    Sag mal, das ist nicht zufällig eine Übungsaufgabe eines Fernlehrgangs, oder so? ?(
    Das iPhone sagt: "Zum Antworten streichen". Wie? Echt Jetzt? Muß ich erst die Wohnung streichen!?
  • Nein nein ich möchte mir das ganze einfach beibringen und mache das für mein eigenes Projekt. Learning by Doing in etwa :)

    Also aktuell habe ich eine Swift.file in der sich ein Structure "User" befindet auf das ich dann in meinem ViewController über den Code


    Quellcode

    1. var users: [User] = [
    2. User(userID: 1, profilePicture: "bild_user29Lifestyle" ,name: "Max Mustermann", question: "Was findet ihr am besten ?"),
    3. User(userID: 2, profilePicture: "bild_user29Lifestyle1", name: "Joel Ertico", question: "Links oder Rechts ?"),
    4. User(userID: 3, profilePicture: "bild_user29Lifestyle2-1", name: "Travis Scott", question: "Welches Cover ?")
    5. ]
    zugreife und bestimme welchen Wert welche Variable hat.
    Ich weiß jetzt nicht genau an was für ein Datenmodell du denkst. Ich meine ich schaffe es ja mir das JSON-Paket auszugeben nur der Zugriff auf die einzelnen Daten fällt mir gerade schwer. Ich weiß nicht wie ich mir bspw. außerhalb der Klammern alle usernamen ausgeben kann.

    Dadurch wird's dann auch schwierig mit der Zuordnung in der TableView da ich nicht weiß was ich der TableViewCell sagen soll....

    Ich bin wirklich noch ein Anfänger aber ich habe so die Vorstellung von wegen das ich mir das JSON-Paket ähnlich wie das Array "users" abspeichern könnte und dann einfach durch dieses Array iteriere, je nachdem welche Variable ich brauche.

    Stehe da irgendwie auf dem Schlauch gerade :/
  • Du hast also schon mal ein users - Array, schön.

    Was mache ich mit einem Array um an dessen Werte zu kommen?
    Korrekt, mit einem Index.

    Welche Möglichkeit habe ich noch?
    Korrekt, eine Schleife.

    Aufgabe: Bastle dir eine Schleife, z.B. mit

    Quellcode

    1. for in
    und lass dir mal die User bzw. dessen Werte ausgeben.

    Da du ja immer noch ein Array hast, kannst du dich mal mit der DataSource der UITableView vertraut machen.

    Was du hier wissen möchtest, sind absolute Basics die auch in den von Apple bereitgestellten Tutorials behandelt werden.

    Anbei mal ein paar Links:

    docs.swift.org/swift-book/LanguageGuide/ControlFlow.html

    developer.apple.com/documentation/uikit/uitableview

    developer.apple.com/library/ar…boutTableViewsiPhone.html

    Nicht wundern, der letzte Link ist etwas "älter" und Objective-C, dein Problem ist aber nicht Swift spezifisch und ein bisschen was musst du davon verstehen :)
  • matz schrieb:

    Was du hier wissen möchtest, sind absolute Basics die auch in den von Apple bereitgestellten Tutorials behandelt werden.
    Okay ja schon klar, so ein krasser Anfänger bin ich dann doch nicht haha. Ich weiß wie ich mir die Daten aus dem "users" Array ziehe, das sollte eher als Beispiel dafür dienen wie es aktuell bei mir aussieht. Aber wahrscheinlich mein Fehler ;)

    Ich habe jetzt mal eine Testdatei angelegt um Missverständnisse zu verhindern :D

    Quellcode

    1. import UIKit
    2. struct RootElement: Codable {
    3. var data: [UserElement]?
    4. }
    5. struct UserElement: Codable {
    6. var question_info: QuestionInfo?
    7. var user_info: UserInfo?
    8. }
    9. struct QuestionInfo: Codable {
    10. var title: String
    11. var id: String
    12. enum CodingKeys: String, CodingKey {
    13. case title
    14. case id
    15. }
    16. init(from decoder: Decoder) throws {
    17. let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
    18. self.title = try valueContainer.decode(String.self, forKey: CodingKeys.title)
    19. self.id = try valueContainer.decode(String.self, forKey: CodingKeys.id)
    20. print("User mit der ID \(id), sagt \(title)")
    21. }
    22. }
    23. struct UserInfo: Codable {
    24. var username: String
    25. enum CodingKeys: String, CodingKey {
    26. case username
    27. }
    28. init(from decoder: Decoder) throws {
    29. let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
    30. self.username = try valueContainer.decode(String.self, forKey: CodingKeys.username)
    31. print("\(username) ")
    32. }
    33. }
    34. extension URL {
    35. func withQueries(_ queries: [String: String]) -> URL? {
    36. var components = URLComponents(url: self, resolvingAgainstBaseURL: true)
    37. components?.queryItems = queries.compactMap{ URLQueryItem(name: $0.0, value: $0.1) }
    38. return components?.url
    39. }
    40. }
    41. class TableViewController: UITableViewController {
    42. @IBOutlet var profileTableView: UITableView!
    43. //var items = [String: String]()
    44. override func viewDidLoad() {
    45. super.viewDidLoad()
    46. let baseURL = URL(string: "http://192.168.178.94/v0.1/questions.php")!
    47. let query: [String: String] = [
    48. "api_key": "DEMO_KEY",
    49. ]
    50. let url = baseURL.withQueries(query)!
    51. let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
    52. let decoder = JSONDecoder()
    53. if let data = data,
    54. let dictionary = try? decoder.decode(RootElement.self, from: data) {
    55. print(dictionary)
    56. }
    57. //let jsonData = try! JSONSerialization.jsonObject(with: data!, options: [])
    58. //self.items = jsonData as! [String: String]
    59. }
    60. task.resume()
    61. }
    62. override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    63. //return items.count
    64. return 1
    65. }
    66. override func numberOfSections(in tableView: UITableView) -> Int {
    67. return 1
    68. }
    69. override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    70. let cell = tableView.dequeueReusableCell(withIdentifier: "UserLine", for: indexPath) as! UserTableViewCell
    71. return cell
    72. }
    73. }
    Alles anzeigen
    Also, wenn ich die App im Simulator öffne sehe ich in der Konsole mein JSON-Paket. In der UserTableViewCell ist lediglich ein Label enthalten. Jetzt meine Frage: Wie kann ich bspw. die usernamen aus dem JSON-Paket dem Label zuweisen, so das die mir alle von oben nach unten in meiner TableView angezeigt werden. Kurz gesagt, was sage ich meiner Cell in cellForRowAt?

    PS: Mein JSON-Paket steht schon weiter oben im Beitrag. Die auskommentierten Zeilen mit "items" waren so ne Idee gewesen die jetzt aber nicht zur Verwirrung beitragen sollen :)

    Ich hoffe so kann mir jemand helfen :D
  • Wenn ich den Swift Code richtig lese, dann ist, nach dem Decodieren des JSON, dictionary vom Typ RootElement, richtig?

    Was spricht denn dagegen anstelle einer lokalen Variable dictionary eine Instanzvariable zu verwenden?

    Da kannst Du dann in den UITableViewDataSource Methode wunderbar drauf zugreifen. ;)
  • MCDan schrieb:

    Wenn ich den Swift Code richtig lese, dann ist, nach dem Decodieren des JSON, dictionary vom Typ RootElement, richtig?

    Was spricht denn dagegen anstelle einer lokalen Variable dictionary eine Instanzvariable zu verwenden?

    Da kannst Du dann in den UITableViewDataSource Methode wunderbar drauf zugreifen. ;)
    Also das hört sich wirklich nach einer guten Idee an, habe das auch gleich mal probiert. Meinst du es in etwa so ?

    Quellcode

    1. import UIKit
    2. struct RootElement: Codable {
    3. var data: [UserElement]?
    4. }
    5. struct UserElement: Codable {
    6. var question_info: QuestionInfo?
    7. var user_info: UserInfo?
    8. }
    9. struct QuestionInfo: Codable {
    10. var title: String
    11. var id: String
    12. enum CodingKeys: String, CodingKey {
    13. case title
    14. case id
    15. }
    16. init(from decoder: Decoder) throws {
    17. let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
    18. self.title = try valueContainer.decode(String.self, forKey: CodingKeys.title)
    19. self.id = try valueContainer.decode(String.self, forKey: CodingKeys.id)
    20. print("User mit der ID \(id), sagt \(title)")
    21. }
    22. }
    23. struct UserInfo: Codable {
    24. var username: String
    25. enum CodingKeys: String, CodingKey {
    26. case username
    27. }
    28. init(from decoder: Decoder) throws {
    29. let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
    30. self.username = try valueContainer.decode(String.self, forKey: CodingKeys.username)
    31. print("\(username) ")
    32. }
    33. }
    34. extension URL {
    35. func withQueries(_ queries: [String: String]) -> URL? {
    36. var components = URLComponents(url: self, resolvingAgainstBaseURL: true)
    37. components?.queryItems = queries.compactMap{ URLQueryItem(name: $0.0, value: $0.1) }
    38. return components?.url
    39. }
    40. }
    41. class TableViewController: UITableViewController {
    42. @IBOutlet var profileTableView: UITableView!
    43. var items = RootElement()
    44. override func viewDidLoad() {
    45. super.viewDidLoad()
    46. let baseURL = URL(string: "http://192.168.178.94/v0.1/questions.php")!
    47. let query: [String: String] = [
    48. "api_key": "DEMO_KEY",
    49. ]
    50. let url = baseURL.withQueries(query)!
    51. let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
    52. let decoder = JSONDecoder()
    53. let data = data!
    54. items = try! decoder.decode(RootElement.self, from: data)
    55. print(items)
    56. //let jsonData = try! JSONSerialization.jsonObject(with: data!, options: [])
    57. //self.items = jsonData as! [String: String]
    58. }
    59. task.resume()
    60. }
    61. override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    62. //return items.count
    63. return 1
    64. }
    65. override func numberOfSections(in tableView: UITableView) -> Int {
    66. return 1
    67. }
    68. override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    69. let cell = tableView.dequeueReusableCell(withIdentifier: "UserLine", for: indexPath) as! UserTableViewCell
    70. return cell
    71. }
    72. }
    Alles anzeigen
    An sich funktioniert es in so weit als das mir in der print-Ausgabe von items, in der Console das JSON_Paket angezeigt wird. Nur leider kann ich von ausserhalb wieder nicht auf die Daten zugreifen da items ausserhalb der Klammern "nil" ist...
  • norbi schrieb:

    Da weigert sich einer, sich selbst über sein eigenes Datenmodell Gedanken zu machen.
    Mach.
    Also weigern möchte ich abstreiten. Versuche schon seit Tagen mein Problem zu lösen und mache mir darüber Gedanken. Was würdest du bezüglich des Datenmodells vorschlagen ?

    Ich meine die einzelnen Structs in meinem Code sind dem JSON-Paket geschuldet. So nun weiß ich das items vom Type RootElement ist und die Werte meines JSON-Pakets beinhaltet. Doch der Zugriff auf genau diese Daten von außerhalb ist das was mich verzweifeln lässt. Deswegen bin ich auch nicht sicher was du nun mit dem Datenmodell genau meinst. Aber ich lasse mich gerne belehren :D

    Ich möchte das ja schließlich auch verstehen :)
  • ThisIsBeat schrieb:

    MCDan schrieb:

    Wenn ich den Swift Code richtig lese, dann ist, nach dem Decodieren des JSON, dictionary vom Typ RootElement, richtig?

    Was spricht denn dagegen anstelle einer lokalen Variable dictionary eine Instanzvariable zu verwenden?

    Da kannst Du dann in den UITableViewDataSource Methode wunderbar drauf zugreifen. ;)
    Also das hört sich wirklich nach einer guten Idee an, habe das auch gleich mal probiert. Meinst du es in etwa so ?
    An sich funktioniert es in so weit als das mir in der print-Ausgabe von items, in der Console das JSON_Paket angezeigt wird. Nur leider kann ich von ausserhalb wieder nicht auf die Daten zugreifen da items ausserhalb der Klammern "nil" ist...

    Hm, bist Du sicher, dass der Data Task schon fertig war und der Completion Handler bereits aufgerufen wurde?
  • MCDan schrieb:

    ThisIsBeat schrieb:

    MCDan schrieb:

    Wenn ich den Swift Code richtig lese, dann ist, nach dem Decodieren des JSON, dictionary vom Typ RootElement, richtig?

    Was spricht denn dagegen anstelle einer lokalen Variable dictionary eine Instanzvariable zu verwenden?

    Da kannst Du dann in den UITableViewDataSource Methode wunderbar drauf zugreifen. ;)
    Also das hört sich wirklich nach einer guten Idee an, habe das auch gleich mal probiert. Meinst du es in etwa so ?An sich funktioniert es in so weit als das mir in der print-Ausgabe von items, in der Console das JSON_Paket angezeigt wird. Nur leider kann ich von ausserhalb wieder nicht auf die Daten zugreifen da items ausserhalb der Klammern "nil" ist...
    Hm, bist Du sicher, dass der Data Task schon fertig war und der Completion Handler bereits aufgerufen wurde?
    Ne leider nicht, muss ich dann nochmal überprüfen. Aber du meinst das schon so wie ich es im Code gemacht habe ?
  • norbi schrieb:

    Wie würdest Du, ohne das JSON im Kopf zu haben, Dein Datenmodell gestalten? So solltest Du es machen, optimal dafür, es zu verwenden.

    Und: mach Dein JSON gut lesbar: jsonformatter.curiousconcept.com/
    Also ich habe daran mal angesetzt und erstmal am JSON Paket was geändert damit das ganze besser lesbar ist und vielleicht auch mehr Sinn macht. Das JSON-Paket schaut nun so aus:

    Quellcode

    1. {"status":"ok","time":1531219037,"data":[{"user_id":"29","user_username":"pascalpru","user_profilepicture":"upload2\/profilbild_user29.jpg","question_id":"1","question_title":"Ja Moin","question_pictures":["GahNiem0","iePh5che","Ooroo7oo","up6pho4A"],"question_date":"1530094596"},{"user_id":"32","user_username":"JoELCHAPO","user_profilepicture":"upload2\/profilbild_user32.png","question_id":"2","question_title":"Was geht","question_pictures":["Oodei3pu","ohreiTe5","reec2Bai"],"question_date":"1530094734"},{"user_id":"34","user_username":"MaxMusti","user_profilepicture":"upload2\/profilbild_user34.png","question_id":"3","question_title":"Valence ist cool","question_pictures":["Ohbii3mu","thae0Eej"],"question_date":"1530094877"},{"user_id":"35","user_username":"philpru98","user_profilepicture":"upload2\/profilbild_user35.png","question_id":"4","question_title":"Coole Schuhe","question_pictures":["Taebui9N","saeSh6ip","up6pho4A"],"question_date":"1530094887"},{"user_id":"36","user_username":"Test","user_profilepicture":"","question_id":"5","question_title":"Welcher Schrank?","question_pictures":["Ejohjuo8","eiHeePh7","naiza3Fe","Woh0yoof"],"question_date":"1530094897"},{"user_id":"37","user_username":"Sonja","user_profilepicture":"","question_id":"6","question_title":"Wo soll ich hin gehen?","question_pictures":["tae9Daet","Aenie3oh"],"question_date":"1530094907"},{"user_id":"38","user_username":"Kalle","user_profilepicture":"","question_id":"7","question_title":"Welchen Urlaub?","question_pictures":["pheWohs6","eiph1Eeg"],"question_date":"1530095252"},{"user_id":"39","user_username":"Manny","user_profilepicture":"","question_id":"8","question_title":"Handy?","question_pictures":["oom0Nu0n","xee7Thah","ak0EeP1U"],"question_date":"1530095262"},{"user_id":"40","user_username":"Tobi","user_profilepicture":"","question_id":"9","question_title":"Was ist geiler?","question_pictures":["uQu0aigh","ienej3Wi","FahH2ohv","yohThie1","ahKai2Ro"],"question_date":"1530095360"},{"user_id":"41","user_username":"derced","user_profilepicture":null,"question_id":"10","question_title":"Was soll ich essen?","question_pictures":["Cexom0ii","ix8IkeiR","Quughu2i","ulaeCoR7"],"question_date":"1530095367"}]}





    So außerdem habe ich jetzt mal den Datenzugriff von außerhalb in etwa hinbekommen. Das ganze schaut nun so aus das ich erstmal eine Swift-Datei namens Structure.swift erstellt habe in der folgender Code enthalten ist:

    Quellcode

    1. import Foundation
    2. struct RootElement: Codable {
    3. var data: [QuestionInfo]?
    4. var status: String
    5. }
    6. struct QuestionInfo: Codable {
    7. var title: String
    8. var id: String
    9. var username: String
    10. enum CodingKeys: String, CodingKey {
    11. case title = "question_title"
    12. case id = "user_id"
    13. case username = "user_username"
    14. }
    15. init(from decoder: Decoder) throws {
    16. let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
    17. self.title = try valueContainer.decode(String.self, forKey: CodingKeys.title)
    18. self.id = try valueContainer.decode(String.self, forKey: CodingKeys.id)
    19. self.username = try valueContainer.decode(String.self, forKey: CodingKeys.username)
    20. print("\(username) mit der ID \(id), sagt \(title)")
    21. }
    22. }
    Alles anzeigen

    Dann gibt es da noch eine Datei die sich FetchInfoController.swift nennt, in der ich das Decoden stattfindet:

    Quellcode

    1. import Foundation
    2. func fetchPhotoInfo(completion: @escaping (RootElement?) -> Void) {
    3. let baseURL = URL(string: "http://192.168.178.94/v0.1/qwert.php")!
    4. let query: [String: String] = [
    5. "api_key": "DEMO_KEY",
    6. ]
    7. let url = baseURL.withQueries(query)!
    8. let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
    9. let decoder = JSONDecoder()
    10. if let data = data,
    11. let dictionary = try? decoder.decode(RootElement.self, from: data) {
    12. completion(dictionary)
    13. } else {
    14. print("Either no data was returned, or data was not serialized.")
    15. completion(nil)
    16. }
    17. }
    18. // send the request
    19. task.resume()
    20. }
    Alles anzeigen

    Und siehe da, ich schaffe es mir die User in meiner TableView innerhalb der Cells von oben nach unten anzeigen zu lassen:

    Quellcode

    1. import UIKit
    2. class TableViewController: UITableViewController {
    3. @IBOutlet var profileTableView: UITableView!
    4. override func viewDidLoad() {
    5. super.viewDidLoad()
    6. }
    7. override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    8. //Zählt die User im Array
    9. //return items.count
    10. return 5
    11. }
    12. override func numberOfSections(in tableView: UITableView) -> Int {
    13. // Die Liste hat nur einen Abschnitt
    14. return 1
    15. }
    16. override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    17. let cell = tableView.dequeueReusableCell(withIdentifier: "UserLine", for: indexPath) as! UserTableViewCell
    18. cell.titleLabel.text = ""
    19. fetchPhotoInfo { (dictionary) in
    20. if let dictionary = dictionary {
    21. DispatchQueue.main.async {
    22. let userInfo = dictionary.data![indexPath.row]
    23. cell.titleLabel.text = userInfo.username
    24. }
    25. }
    26. }
    27. return cell
    28. }
    29. }
    Alles anzeigen
    So und vielleicht ist es jemandem von euch bereits aufgefallen aber in numberOfRowsInSection habe ich einfach eine Zahl eingetragen und mir werden auch nur die ersten fünf Übernamen angezeigt. Normalerweise entscheide wie viele Zellen angezeigt werden in dem ich das Array in dem die Daten enthalten sind einfach zähle mit Count.

    Nur genau das bekomme ich absolut nicht hin, ich hatte es beispielsweise schon wie folgt probiert das das hat natürlich nicht funktioniert. Hat jemand ne Idee wie ich das hinbekommen kann ?


    Quellcode

    1. let test = [RootElement]()
    2. for baum in test {
    3. return (baum.data?.count)!
    4. }
  • MCDan schrieb:

    Du lädst ja bei jedem Aufruf von tableView(_:cellForRowAt:) die Daten immer wieder neu vom Server. Warum? ?(

    Dein vorheriger Code hätte doch wunderbar funktioniert. Nach dem Laden und Decodieren der Daten hätte ggf. nur ein reloadData() bei dem TableView gefehlt.
    Tut mir leid das ich nicht geantwortet habe, hatte etwas viel um die Ohren.
    In wie fern ein reloadData() bzw. was meinst du damit ? In der Console sagt er mir nämlich jedes mal das die Werte "nil" sind :/ Aber dadurch das mir das in der Console schon angezeigt wird, gehe ich mal davon aus das der Completion Handler auch schon fertig ist.

    Nur nochmal damit wir uns auch nicht falsch verstehen... Du meintst ich soll es so machen ?:

    Quellcode

    1. import UIKit
    2. struct RootElement: Codable {
    3. var data: [UserElement]?
    4. }
    5. struct UserElement: Codable {
    6. var question_info: QuestionInfo?
    7. var user_info: UserInfo?
    8. }
    9. struct QuestionInfo: Codable {
    10. var title: String
    11. var id: String
    12. enum CodingKeys: String, CodingKey {
    13. case title
    14. case id
    15. }
    16. init(from decoder: Decoder) throws {
    17. let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
    18. self.title = try valueContainer.decode(String.self, forKey: CodingKeys.title)
    19. self.id = try valueContainer.decode(String.self, forKey: CodingKeys.id)
    20. print("User mit der ID \(id), sagt \(title)")
    21. }
    22. }
    23. struct UserInfo: Codable {
    24. var username: String
    25. enum CodingKeys: String, CodingKey {
    26. case username
    27. }
    28. init(from decoder: Decoder) throws {
    29. let valueContainer = try decoder.container(keyedBy: CodingKeys.self)
    30. self.username = try valueContainer.decode(String.self, forKey: CodingKeys.username)
    31. print("\(username) ")
    32. }
    33. }
    34. extension URL {
    35. func withQueries(_ queries: [String: String]) -> URL? {
    36. var components = URLComponents(url: self, resolvingAgainstBaseURL: true)
    37. components?.queryItems = queries.compactMap{ URLQueryItem(name: $0.0, value: $0.1) }
    38. return components?.url
    39. }
    40. }
    41. class TableViewController: UITableViewController {
    42. @IBOutlet var profileTableView: UITableView!
    43. var items = RootElement()
    44. override func viewDidLoad() {
    45. super.viewDidLoad()
    46. let baseURL = URL(string: "https://valapi.cedsoft.de/v0.1/questions.php")!
    47. let query: [String: String] = [
    48. "api_key": "DEMO_KEY",
    49. ]
    50. let url = baseURL.withQueries(query)!
    51. let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
    52. let decoder = JSONDecoder()
    53. let data = data!
    54. self.items = try! decoder.decode(RootElement.self, from: data)
    55. print(self.items)
    56. //let jsonData = try! JSONSerialization.jsonObject(with: data!, options: [])
    57. //self.items = jsonData as! [String: String]
    58. }
    59. task.resume()
    60. }
    61. override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    62. //return items.count
    63. return 1
    64. }
    65. override func numberOfSections(in tableView: UITableView) -> Int {
    66. return 1
    67. }
    68. override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    69. let cell = tableView.dequeueReusableCell(withIdentifier: "UserLine", for: indexPath) as! UserTableViewCell
    70. return cell
    71. }
    72. }
    Alles anzeigen