Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 623
MarkP Avatar asked Jan 29 '16 01:01

MarkP


2 Answers

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()
    }
}
like image 75
Radosław Cięciwa Avatar answered Sep 20 '22 20:09

Radosław Cięciwa


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 i.e:

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!}))

        }

    }

}
like image 42
Ankur Avatar answered Sep 23 '22 20:09

Ankur