Dynamically Generate UITableView Cells and Headrs

Project files:

https://jumpshare.com/v/Otai3BBXYwfvyz8jb53k

(Would be wise to view these to see structure of project)

Problem:

Ok, so i'm following a tutorial that creates a UITableView with headers and then cell content.

The code worked and runs fine, Now I want to extend beyond that tutorial and dynamically load that content using alamofire and SwiftyJSON.

In the tutorial, the code used is like so:

func getSectionsFromData() -> [Sections] {

    var sectionsArray = [Sections]()

    let animals = Sections(title: "Animals", objects: ["Cats", "Dogs", "Birds", "Lions"])


    sectionsArray.append(animals)

    return sectionsArray


}

What I tried to do was:

Alamofire.request(.GET, url).validate().responseJSON { response in
        switch response.result {
        case .Success:
            if let value = response.result.value {
                let json = JSON(value)

                for (_, subJson) in json {
                    for (year, content) in subJson {
                        let title = year
                        let objects = content

                        sectionsArray.append(Sections(title: title, objects: objects))

                    }

                }
            }
        case .Failure(let error):
            print(error)
        }
    }

If I print out the results they show in the console - so I know the getting and looping of the JSON works. I then added in

let title = year
let objects = content

sectionsArray.append(Sections(title: title, objects: objects))

But on this line:

sectionsArray.append(Sections(title: title, objects: objects))

I get this error:

cannot convert value of type 'JSON' to expected argument type '[String]'

Here is the JSON I am using:

 {"posts": [
 {
    "Category1": [
        "Post1cat1"
    ],
    "Category2": [
        "Post1cat2",
        "Post2cat2"
    ]
 }
 ]}

Can someone help me? I might be going in the wrong direction here I want to loop through the JSON and display the categories as headers and the posts in a cell of a table.

edit: 1/29/2016

so, I changed the loop to:

for (_, subJson) in json {
                for (index, data) in subJson {
                    for (title, objects) in data {
                        sectionsArray.append(Sections(title: title, objects: objects.self.arrayValue.map { $0.string!}))


                    }

                }

            }

Still no luck. When I add in some prints (under: sectionsArray.append) to test if there is data:

print("--")
print(title)
print(objects.self.arrayValue.map { $0.string!})
print(Sections(title: title, objects: objects.self.arrayValue.map { $0.string!}))

I get this result in the console:

--

Category1

["Post1cat1"]

Sections(headings: "Category1", items: ["Post1cat1"])

--

Category2

["Post1cat2", "Post2cat2"]

Sections(headings: "Category2", items: ["Post1cat2", "Post2cat2"])

Which shows that the information is there, however when I run the app there are still no results form he JSON just the originally defined section and cells above.


In second parsing method (after edit), you're iterating on array in last loop, so either you could create array there and add each element separately, as in example:

for (title, data) in subJson {
    var elements: [String] = []

    for (_, object) in data {
        if let stringELement = object.rawString() {
            elements.append(stringELement)
        }
    }

    sectionsArray.append(Sections(title: title, objects: elements))
}

or if you prefer you can use casted raw array from JSON object as in this example:

for (_, subJson) in json["posts"] {
    for (title, data) in subJson {
        let optionalCastedObjects = data.arrayObject as? [String]
        let unwrappedObjects = optionalCastedObjects ?? []
        let section = Sections(title: title, objects: unwrappedObjects)

        sectionsArray.append(section)                        
    }
}

That should fix mentioned compilation issue.

But in the end remember that you're using async callback (in your GET request ) in synchronous getSectionsFromData method. And you're always will return array before the values from that callback ( clojure ) will append new data. That will cause, that you're never display the data that you fetched that way.

UPDATE

To do that you should refactor your getSectionsFromData method as below.

func getSectionsFromData(completion: ([Sections]) -> ()) {
    var sectionsArray = [Sections]()

    Alamofire.request(.GET, url).validate().responseJSON { response in
        switch response.result {
        case .Success:
            if let value = response.result.value {
                let json = JSON(value)

                for (_, subJson) in json["posts"] {
                    for (title, data) in subJson {
                        let optionalCastedObjects = data.arrayObject as? [String]
                        let unwrappedObjects = optionalCastedObjects ?? []
                        let section = Sections(title: title, objects: unwrappedObjects)

                        sectionsArray.append(section)
                    }
                }

                completion(sectionsArray)
            }
        case .Failure(let error):
            print(error)
        }
    }
}

And relevant parts in your UITableViewController class.

var sections: [Sections] = []

override func viewDidLoad() {
    super.viewDidLoad()

    SectionsData().getSectionsFromData { [weak self](sections: [Sections]) -> () in
        self?.sections = sections
        self?.tableView.reloadData()
    }
}

Your second loop is on the array object hence in that loop year is index value and content is the object at that index.

You need to implement an additional loop to fix the problem ie:

for (_, subJson) in json {
    for (index, data) in subJson {
        for (title, objects) in data {
            sectionsArray.append(Sections(title: title, objects: objects.arrayValue.map { $0.string!}))

        }

    }

}

From the SwiftyJSON documentation:

for (key,subJson):(String, JSON) in json {
   //Do something you want
}

This indicates that subJson is of type JSON. However, your Sections constructor in the first example is:

Sections(title: "Animals", objects: ["Cats", "Dogs", "Birds", "Lions"])

In your second example, you're calling it as:

Sections(title: title, objects: objects)

Unless you have changed the constructor, it's expecting objects to be an array of strings, not JSON. This is why you're getting an error saying Swift can't convert JSON to String. In your case, the objects JSON is actually an array of strings, so you need to use something like:

Sections(title: title, objects: objects.arrayValue.map { $0.string!})
链接地址: http://www.djcxy.com/p/31780.html

上一篇: 关于如何记录Websocket API的建议

下一篇: 动态生成UITableView单元和头部