I'm trying to parse a JSON file to my code.
So, far I have managed to do so except for one key (genre) that has an array of values.
I want to know how can I parse it so I can present it in a UILabel?
JSON data in file:
[{
"title": "Dawn of the Planet of the Apes",
"image": "http://api.androidhive.info/json/movies/1.jpg",
"rating": 8.3,
"releaseYear": 2014,
"genre": ["Action", "Drama", "Sci-Fi"]
},
{
"title": "District 9",
"image": "http://api.androidhive.info/json/movies/2.jpg",
"rating": 8,
"releaseYear": 2009,
"genre": ["Action", "Sci-Fi", "Thriller"]
},
{
"title": "Transformers: Age of Extinction",
"image": "http://api.androidhive.info/json/movies/3.jpg",
"rating": 6.3,
"releaseYear": 2014,
"genre": ["Action", "Adventure", "Sci-Fi"]
},
{
"title": "X-Men: Days of Future Past",
"image": "http://api.androidhive.info/json/movies/4.jpg",
"rating": 8.4,
"releaseYear": 2014,
"genre": ["Action", "Sci-Fi", "Thriller"]
},
{
"title": "The Machinist",
"image": "http://api.androidhive.info/json/movies/5.jpg",
"rating": 7.8,
"releaseYear": 2004,
"genre": ["Drama", "Thriller"]
},
{
"title": "The Last Samurai",
"image": "http://api.androidhive.info/json/movies/6.jpg",
"rating": 7.7,
"releaseYear": 2003,
"genre": ["Action", "Drama", "History"]
},
{
"title": "The Amazing Spider-Man 2",
"image": "http://api.androidhive.info/json/movies/7.jpg",
"rating": 7.3,
"releaseYear": 2014,
"genre": ["Action", "Adventure", "Fantasy"]
},
{
"title": "Tangled",
"image": "http://api.androidhive.info/json/movies/8.jpg",
"rating": 7.9,
"releaseYear": 2010,
"genre": ["Action", "Drama", "Sci-Fi"]
},
{
"title": "Rush",
"image": "http://api.androidhive.info/json/movies/9.jpg",
"rating": 8.3,
"releaseYear": 2013,
"genre": ["Animation", "Comedy", "Family"]
},
{
"title": "Drag Me to Hell",
"image": "http://api.androidhive.info/json/movies/10.jpg",
"rating": 6.7,
"releaseYear": 2009,
"genre": ["Horror", "Thriller"]
},
{
"title": "Despicable Me 2",
"image": "http://api.androidhive.info/json/movies/11.jpg",
"rating": 7.6,
"releaseYear": 2013,
"genre": ["Animation", "Comedy", "Family"]
},
{
"title": "Kill Bill: Vol. 1",
"image": "http://api.androidhive.info/json/movies/12.jpg",
"rating": 8.2,
"releaseYear": 2003,
"genre": ["Action", "Crime"]
},
{
"title": "A Bug's Life",
"image": "http://api.androidhive.info/json/movies/13.jpg",
"rating": 7.2,
"releaseYear": 1998,
"genre": ["Animation", "Adventure", "Comedy"]
},
{
"title": "Life of Brian",
"image": "http://api.androidhive.info/json/movies/14.jpg",
"rating": 8.9,
"releaseYear": 1972,
"genre": ["Comedy"]
},
{
"title": "How to Train Your Dragon",
"image": "http://api.androidhive.info/json/movies/15.jpg",
"rating": 8.2,
"releaseYear": 2010,
"genre": ["Animation", "Adventure", "Family"]
}]
Movie class:
import UIKit
class Movie {
var title = ""
var image = ""
var rating = 0.0
var releaseYear = 0
init(object: [String: AnyObject]) {
self.title = object["title"] as! String
self.image = object["image"] as! String
self.rating = object["rating"] as! Double
self.releaseYear = object["releaseYear"] as! Int
}
init() {
}
}
MovieCell Class:
import UIKit
import SDWebImage
class MovieCell: UITableViewCell {
#IBOutlet weak var titleLbl: UILabel!
#IBOutlet weak var releaseYearLbl: UILabel!
#IBOutlet weak var ratingLbl: UILabel!
#IBOutlet weak var movieImage: UIImageView!
#IBOutlet weak var genreLbl: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
func createCell(movie: Movie) {
self.titleLbl.text = movie.title
self.releaseYearLbl.text = "\(movie.releaseYear)"
self.ratingLbl.text = "\(movie.rating) ⭐️"
movieImage.layer.cornerRadius = 10.0
movieImage.clipsToBounds = true
self.movieImage.sd_setImage(with: URL(string: movie.image))
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Swift 3.0
Just analyse below code and apply it to your issue
The Movie class becomes,
class Movie {
var title = ""
var image = ""
var rating = 0.0
var releaseYear = 0
var genre:String?
init(object: [String: AnyObject]) {
self.title = object["title"] as! String
self.image = object["image"] as! String
self.rating = object["rating"] as! Double
self.releaseYear = object["releaseYear"] as! Int
let genreArray = object["genre"] as! [String]
/*Whatever you want do here with genre. I thought you need whole array to one readable String*/
for strings in genreArray{
self.genre = self.genre == nil ? strings : self.genre!+" "+strings
}
}
}
Class that had UITableView
The global variable of the class is,
var movieData = Array<Movie>()
The JSON parse will becomes,
if let json = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as? Array<Dictionary<String, AnyObject>>{
for object in json{
self.movieData.append(Movie(object: object))
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
UITableView datasource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return movieData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "cell", for:indexPath)
let tableObject:Movie = self.movieData[indexPath.row]
cell.textLabel?.text = tableObject.genre //This way you will be get all values and apply it to whatever you want...
return cell
}
OUTPUT:-
Related
I've created NSObject class for "CurrentUser",
here, sign-up API will call & response data will insert into the "CurrentUser" model.
This is one type of global model, like in any screen user_logic_details will fetch, modify & save.
Example :
let loginuser : CurrentUser = CurrentUser.getLoginData()!
loginuser.email = "abc#gmail.com"
CurrentUser.saveLoginData(loginData: loginuser)
// working
let email = CurrentUser.getLoginData()?.email ?? "" // i'll get "abc#gmail.com"
in the above example if I write the below code then it shows nil data
let loginuser : CurrentUser = CurrentUser.getLoginData()!
loginuser.email = "abc#gmail.com"
CurrentUser.saveLoginData(loginData: loginuser)
// working
let email = CurrentUser.getLoginData()?.email ?? "" // i'll get "abc#gmail.com"
// not working
let roleName = CurrentUser.getLoginData()?.roles?.name ?? "" // showing get ""
I'm not able to find exact issues here,
Check below the code of how I use the model class, saving data into UserDefaults & retrieve data from the model.
class CurrentUser: NSObject, NSCoding, NSKeyedUnarchiverDelegate {
var email : String!
var roles : UserRole!
private var _isLoggedIn = false
required convenience init(coder aDecoder: NSCoder) {
self.init()
roles = aDecoder.decodeObject(forKey: "roles") as? UserRole
email = aDecoder.decodeObject(forKey: "email") as? String
}
func encode(with aCoder: NSCoder) {
aCoder.encode(email, forKey: "email")
aCoder.encode(roles, forKey: "roles")
}
class func getLoginData() -> CurrentUser? {
let userDefaults = UserDefaults.standard
if let UserData = userDefaults.object(forKey: "loginUser") {
guard let unarchivedFavorites = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(UserData as! Data)
else {
return nil
}
return unarchivedFavorites as? CurrentUser
} else {
return CurrentUser()
}
}
class func saveLoginData(loginData: CurrentUser?) {
do {
let encodedData = try NSKeyedArchiver.archivedData(withRootObject: loginData as Any, requiringSecureCoding: false)
let userDefaults: UserDefaults = UserDefaults.standard
userDefaults.set(encodedData, forKey: "loginUser")
userDefaults.synchronize()
} catch {
print("Couldn't write file")
}
}
func unarchiver(_ unarchiver: NSKeyedUnarchiver, cannotDecodeObjectOfClassName name: String, originalClasses classNames: [String]) -> AnyClass? {
print("classNames", classNames)
return nil
}
}
class UserRole: NSObject, NSCoding {
var name : String!
required convenience init(coder aDecoder: NSCoder) {
self.init()
name = aDecoder.decodeObject(forKey: "name") as? String
}
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: "name")
}
}
The above model is for reference purposes.
I need to convert the below Response to the whole model class
{
"addressList": [
{
"addressLabel": "string",
"city": "string",
"country": "string",
"createdAt": "2022-03-16T12:10:41.148Z",
"homePhone": "string",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"isDefault": true,
"isDeleted": true,
"state": "string",
"streetAddress": "string",
"updatedAt": "2022-03-16T12:10:41.148Z",
"version": 0,
"zip": "string"
}
],
"ageRange": "string",
"badges": [
{
"badge": {
"createdAt": "2022-03-16T12:10:41.148Z",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"image": "string",
"isDeleted": true,
"label": "string",
"name": "string",
"status": "ACTIVE",
"updatedAt": "2022-03-16T12:10:41.148Z",
"users": [
null
],
"version": 0
},
"userBadgeId": {
"badgeId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"userId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
}
],
"classesTaken": 0,
"createdAt": "2022-03-16T12:10:41.148Z",
"deviceList": [
{
"createdAt": "2022-03-16T12:10:41.148Z",
"deviceId": "string",
"deviceName": "string",
"deviceType": "ANDROID",
"display": "string",
"fcmToken": "string",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"isDeleted": true,
"osVersion": "string",
"updatedAt": "2022-03-16T12:10:41.148Z",
"version": 0
}
],
"displayName": "string",
"displayPic": "string",
"dob": "2022-03-16T12:10:41.148Z",
"email": "string",
"experience": 0,
"firebaseToken": "string",
"firebaseUserId": "string",
"followerCount0l": 0,
"fullName": "string",
"gender": "FEMALE",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"isDeleted": true,
"lastLoginTime": "2022-03-16T12:10:41.148Z",
"location": "string",
"phoneNumber": "string",
"roles": [
{
"createdAt": "2022-03-16T12:10:41.148Z",
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"isDeleted": true,
"name": "ROLE_ADMIN",
"updatedAt": "2022-03-16T12:10:41.148Z",
"version": 0
}
],
"rubyBalance": 0,
"signupDateTime": "2022-03-16T12:10:41.148Z",
"signupSource": {
"buildNumber": "string",
"deviceId": "string",
"deviceType": "ANDROID",
"osVersion": "string"
},
"status": "ACTIVE",
"studentsTaught": 0,
"updatedAt": "2022-03-16T12:10:41.148Z",
"userInterest": [
"string"
],
"userName": "string",
"version": 0
}
If anyone has a better way to do it or a better solution, please answer it.
Your code reads like Objective-C from a few years ago. Something more modern and Swift-like might be:
#propertyWrapper
struct UserDefaultsCodableWrapper<T: Codable> {
let key: String
let defaultValue: T?
init(_ key: String, defaultValue: T?) {
self.key = key
self.defaultValue = defaultValue
}
var wrappedValue: T? {
get {
guard let data = UserDefaults.standard.data(forKey: key),
let decoded = try? JSONDecoder().decode(T.self, from: data)
else { return defaultValue }
return decoded
}
set {
let encoded = try? JSONEncoder().encode(newValue)
UserDefaults.standard.set(encoded, forKey: key)
}
}
}
struct User: Codable {
var email: String // TODO make a codable "Email" struct type that validates its input, no invalid strings allowed
var roles: [UserRole]
}
struct UserRole: Codable {
var name: String
}
class AppState {
#UserDefaultsCodableWrapper("CurrentUser", defaultValue: nil)
var currentUser: User?
}
class ViewController: UIViewController {
let state = AppState()
override func viewDidLoad() {
super.viewDidLoad()
print(String(describing: state.currentUser)) // nil
state.currentUser = User(email: "foo#bar.baz", roles: [.init(name: "Foo"), .init(name: "Bar")])
print(String(describing: state.currentUser)) // Optional(User...
Also worth pointing you to app.quicktype.io which can generate you codable models from your json.
I'm new in iOS programming language and I'm trying to fetch data from a WordPress JSON into a table view. I'm encountering the error:
value of type 'Any' has no subscripts
when I try to instantiate the object of the array.
Here is the JSON:
[
{
"id": 1352,
"date": "2019-10-16T09:30:39",
"date_gmt": "2019-10-16T09:30:39",
"guid": {
"rendered": "https://wepress.comm-it.it/ddjhgtr/"
},
"modified": "2019-10-16T13:23:41",
"modified_gmt": "2019-10-16T13:23:41",
"slug": "ddjhgtr",
"status": "publish",
"type": "post",
"link": "https://wepress.comm-it.it/ddjhgtr/",
"title": "ddjhgtr",
"content": "eryyreytyvggjggvhghhh",
"excerpt": "eryyreyty",
"author": 2,
"featured_media": {
"id": 1418,
"url": "https://wepress.comm-it.it/wp-content/uploads/2019/10/10-62.jpeg"
},
"comment_status": "open",
"ping_status": "open",
"sticky": false,
"template": "",
"format": "standard",
"meta": [],
"categories": [
{
"id": 1,
"name": "Uncategorized",
"description": ""
}
],
"tags": [],
"_links": {
"self": [
{
"href": "https://wepress.comm-it.it/wp-json/wp/v2/posts/1352"
}
],
"collection": [
{
"href": "https://wepress.comm-it.it/wp-json/wp/v2/posts"
}
],
"about": [
{
"href": "https://wepress.comm-it.it/wp-json/wp/v2/types/post"
}
],
"author": [
{
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/users/2"
}
],
"replies": [
{
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/comments?post=1352"
}
],
"version-history": [
{
"count": 3,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/posts/1352/revisions"
}
],
"predecessor-version": [
{
"id": 1419,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/posts/1352/revisions/1419"
}
],
"wp:featuredmedia": [
{
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/media/1418"
}
],
"wp:attachment": [
{
"href": "https://wepress.comm-it.it/wp-json/wp/v2/media?parent=1352"
}
],
"wp:term": [
{
"taxonomy": "category",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/categories?post=1352"
},
{
"taxonomy": "post_tag",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/tags?post=1352"
},
{
"taxonomy": "difficulty-level-course",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/difficulty-level-course?post=1352"
},
{
"taxonomy": "category-course",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/category-course?post=1352"
},
{
"taxonomy": "location-course",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/location-course?post=1352"
},
{
"taxonomy": "duration-course",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/duration-course?post=1352"
}
],
"curies": [
{
"name": "wp",
"href": "https://api.w.org/{rel}",
"templated": true
}
]
}
},
....(many other News objects)
{
"id": 774,
"date": "2019-10-07T07:30:51",
"date_gmt": "2019-10-07T07:30:51",
"guid": {
"rendered": "https://wepress.comm-it.it/name-here/"
},
"modified": "2019-10-07T07:30:51",
"modified_gmt": "2019-10-07T07:30:51",
"slug": "name-here",
"status": "publish",
"type": "post",
"link": "https://wepress.comm-it.it/name-here/",
"title": "name here",
"content": "desc here",
"excerpt": "desc here",
"author": 2,
"featured_media": null,
"comment_status": "open",
"ping_status": "open",
"sticky": false,
"template": "",
"format": "standard",
"meta": [],
"categories": [
{
"id": 1,
"name": "Uncategorized",
"description": ""
}
],
"tags": [],
"_links": {
"self": [
{
"href": "https://wepress.comm-it.it/wp-json/wp/v2/posts/774"
}
],
"collection": [
{
"href": "https://wepress.comm-it.it/wp-json/wp/v2/posts"
}
],
"about": [
{
"href": "https://wepress.comm-it.it/wp-json/wp/v2/types/post"
}
],
"author": [
{
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/users/2"
}
],
"replies": [
{
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/comments?post=774"
}
],
"version-history": [
{
"count": 0,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/posts/774/revisions"
}
],
"wp:attachment": [
{
"href": "https://wepress.comm-it.it/wp-json/wp/v2/media?parent=774"
}
],
"wp:term": [
{
"taxonomy": "category",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/categories?post=774"
},
{
"taxonomy": "post_tag",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/tags?post=774"
},
{
"taxonomy": "difficulty-level-course",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/difficulty-level-course?post=774"
},
{
"taxonomy": "category-course",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/category-course?post=774"
},
{
"taxonomy": "location-course",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/location-course?post=774"
},
{
"taxonomy": "duration-course",
"embeddable": true,
"href": "https://wepress.comm-it.it/wp-json/wp/v2/duration-course?post=774"
}
],
"curies": [
{
"name": "wp",
"href": "https://api.w.org/{rel}",
"templated": true
}
]
}
}
]
For the moment I'm interested to get just the image (featured_media), title and content of these "objects" and put them into the tableView. Indeed here are the structs that I created for them:
The news represents the struct contained into the JSON array
struct News {
public var id: Int
public var title: String
public var content: String
public var image: FeaturedMedia
}
struct FeaturedMedia {
public var id: Int
public var url: String
}
Here is the UITableViewCell class:
import UIKit
class NewsTableViewCell: UITableViewCell {
#IBOutlet weak var newsImage: UIImageView!
#IBOutlet weak var newsTitle: UILabel!
#IBOutlet weak var newsContent: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
And here the UITableViewController class:
import UIKit
import Alamofire
import Alamofire_SwiftyJSON
import SwiftyJSON
class NewsTableViewController: UITableViewController {
var newsList: [News] = [News]()
func parseJsonNews() {
DispatchQueue.main.async {
Alamofire.request("link request", method: .get).responseJSON { (response) in
switch response.result {
case .success(let value):
let news = [value]
print(news) // here in console it prints correctly the json, starting with [<__NSArrayI 0x6000001a9e60 ....
for new in news {
let title = new["title"]
print(title)
}
print(newsss)
self.tableView.reloadData()
case.failure(let error):
print(error.localizedDescription)
}
})
}
}
override func viewDidLoad() {
super.viewDidLoad()
parseJsonNews()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.newsList.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "newsCell", for: indexPath) as? NewsTableViewCell
// Configure the cell...
let imageUrl = URL.init(string: newsList[indexPath.row].featuredMedia.url)
cell?.newsTitle.text = self.newsList[indexPath.row].title
cell?.newsContent.text = self.newsList[indexPath.row].content
cell.newsImage.load(url: imageUrl!)
return cell!
}
}
extension UIImageView {
func load(url: URL) {
DispatchQueue.global().async { [weak self] in
if let data = try? Data(contentsOf: url) {
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self?.image = image
}
}
}
}
}
}
Looking for a solution, I just found many ways to parse dictionary JSON, but in this case, it is an array so I modified the code as you read at parseJsonNews method but it doesn't work properly.
Would be grateful for any help.
You can decode with Codable like this:
let data = try? JSONDecoder().decode([DummyData].self, from: jsonData)
But first, all of your models must comform Codable protocol. For example:
struct DummyData: Codable {
let id: Int
let date, dateGmt: String
let modified, modifiedGmt, slug, status: String
let type: String
let link: String
let title, content, excerpt: String
let author: Int
let commentStatus, pingStatus: String
let sticky: Bool
let template, format: String
enum CodingKeys: String, CodingKey {
case id, date
case dateGmt = "date_gmt"
case modified
case modifiedGmt = "modified_gmt"
case slug, status, type, link, title, content, excerpt, author
case commentStatus = "comment_status"
case pingStatus = "ping_status"
case sticky, template, format
}
}
A couple of things:
The error value of type 'Any' has no subscripts, refers to your line let title = new["title"].
the response results from Alamofire in the .success enum returns a type of Any,
this is true to the whole array of data that you fetched.
The Any type in swift doesn't have any subscripts implementations (i.e: you cannot access vars inside it using the following syntax obj['MY_VAR_NAME'].
In order to access the title from your news object like so let title = new["title"], you have to first cast the objects to a dictionary, this could be done like this:
// ...
let news = [value]
print(news)
for new in news {
if let obj = new as? [String: Any] {
let title = obj["title"]
print(title)
}
}
// ...
In order to parse/use your custom structs, they must first comply to swift's Codable protocol.
/// Example show only News, but the same which be used for FeaturedMedia
struct News {
public var id: Int
public var title: String
public var content: String
public var image: FeaturedMedia?
init?(jsonString: String) {
guard let data = jsonString.data(using: .utf8) else {
return nil
}
guard let object = News(data: data) else {
return nil
}
self = object
}
init?(data: Data) {
guard let object = try? JSONDecoder().decode(News.self, from:
data) else {
return nil
}
self = object
}
// Optional, for custom key names (i.e: "image" instead of "featured_media"
private enum CodingKeys: String, CodingKey {
case id = "id"
case image = "featured_media"
// etc..
}
}
After you've done number 4, you can then init your objects like so:
// ...
let news = [value]
print(news)
for new in news {
if let obj = News(new) {
/// obj is now a News object
let title = obj.title
print(title)
}
}
// ...
if you are in pursuit for even more info (for example to init the whole array)
check out this
I hope I've cleared things up:)
func ComplainData() {
let semaphore = DispatchSemaphore(value: 0)
var request = URLRequest(url: URL(string: Constant.localBaseurl2 + "compID") !, timeoutInterval: Double.infinity)
request.httpMethod = "GET"
let task = URLSession.shared.dataTask(with: request) {
data,
response,
error in
if let response = response {
let nsHTTPResponse = response as!HTTPURLResponse
print(nsHTTPResponse)
}
if let error = error {
print("\(error)")
return
}
if let data = data {
DispatchQueue.main.async {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase //or any other Decoder\
do {
let jsonDecoder = JSONDecoder()
let memberRecord =
try jsonDecoder.decode(COMPLAINTSVC.GetComplaints.self, from: data)
print(memberRecord.message)
for detailData in memberRecord.message {
print(detailData)
}
} catch {
print(error.localizedDescription)
}
}
}
semaphore.signal()
}
task.resume()
semaphore.wait()
}
This is how my cell looks like
This is the structuring of my cell
I have a JSON format looks like this:
{
"status": true,
"session": true,
"make": "Ford",
"year": "2015",
"model": "EXPLORER",
"trim": "Base",
"engine": "3.5L V6 - Gas",
"make_id": "96",
"year_id": "100",
"model_id": "284",
"trim_id": "358",
"engine_id": "510",
"title": "Ford 2015 EXPLORER Base 3.5L V6 - Gas - Alternator",
"group_image": "http://www.orouad.com/test_aspns/image/catalog/Ford/67dc394bb5c7839fe09bcbae85210b90.svg",
"parts": [
{
"product_id": "7760",
"group_id": "317991",
"part_number": "DG1Z-10346-B",
"part_name": "Alternator",
"part_image": "http://www.orouad.com/test_aspns/image/cache/placeholder-130x130.png",
"description": "",
"part_index": "1",
"quantity": "0",
"price": "SAR 0.00",
"after_market": [],
"superseded": [
{
"part_id": "11695",
"part_no": "AA5Z*10346*B",
"manufacturer": null,
"description": "Alternator",
"price": "SAR 0.00",
"quantity": "0"
},
{
"part_id": "12187",
"part_no": "GL*980*",
"manufacturer": null,
"description": "Alternator",
"price": "SAR 0.00",
"quantity": "0"
}
]
},
{
"product_id": "7761",
"group_id": "318048",
"part_number": "DG1Z-10346-F",
"part_name": "Alternator",
"part_image": "http://www.orouad.com/test_aspns/image/cache/placeholder-130x130.png",
"description": "",
"part_index": "1",
"quantity": "0",
"price": "SAR 0.00",
"after_market": [],
"superseded": [
{
"part_id": "11581",
"part_no": "8A4Z*10346*A",
"manufacturer": null,
"description": "Alternator",
"price": "SAR 0.00",
"quantity": "0"
},
{
"part_id": "12032",
"part_no": "DG1Z*10346*A",
"manufacturer": null,
"description": "Alternator",
"price": "SAR 0.00",
"quantity": "0"
},
{
"part_id": "12186",
"part_no": "GL",
"manufacturer": null,
"description": "Alternator",
"price": "SAR 7.00",
"quantity": "0"
}
]
},
{
"product_id": "7762",
"group_id": "318101",
"part_number": "GB5Z-10346-C",
"part_name": "Alternator",
"part_image": "http://www.orouad.com/test_aspns/image/cache/placeholder-130x130.png",
"description": "",
"part_index": "1",
"quantity": "0",
"price": "SAR 0.00",
"after_market": [],
"superseded": [
{
"part_id": "11848",
"part_no": "BL3Z-10346-A",
"manufacturer": null,
"description": "Alternator",
"price": "SAR 0.00",
"quantity": "0"
},
{
"part_id": "12079",
"part_no": "DG1Z-10346-C",
"manufacturer": null,
"description": "Alternator",
"price": "SAR 0.00",
"quantity": "0"
},
{
"part_id": "12186",
"part_no": "GL",
"manufacturer": null,
"description": "Alternator",
"price": "SAR 7.00",
"quantity": "0"
}
]
}
I want to show all "parts" as well as "aftermarket" and "superseded" parts if there is any value inside array "aftermarket" and "superseded" otherwise hide the aftermarket and superseded view and just show the parts view.
My problem is how do I show multiple views of aftermarket and superseded if there is multiple value inside these array.
This is the code to show if there is only one value in aftermarket or superseded
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return partsData.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "partsDetailCell") as! VehiclePartsDetailCell
cell.layer.borderColor = UIColor.white.cgColor
cell.layer.borderWidth = 1
let partData = partsData[indexPath.row]
if (partData.afterMarket?.isEmpty)!{
cell.bottomView.isHidden = true
}else{
cell.bottomView.isHidden = false
cell.bottomPartLbl.text = partData.afterMarket![0].partNo
cell.bottomDesLbl.text = partData.afterMarket![0].description
cell.bottomPriceLbl.text = partData.afterMarket![0].price
}
cell.serialNoLbl.text = partData.partIndex
cell.partNoLbl.text = partData.partNumber
cell.descriptionLbl.text = partData.partName
cell.priceLbl.text = partData.price
cell.cartBtn.setImage(UIImage(named: "cart.png"), for: .normal)
return cell
}
I anyone provide any suggestion on how to populate data or to use multiple cells inside tableview.
This is pseudo code just for example, you have to modify it.
First you have to set cell size with this method
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return currentCellSize + partsData[indexPath.row].superseded.count * supersededSize + afmNormalHight * partsData[indexPath.row].afterMarket.count
}
After taht you need to change your cell creation to be like this
var currentCount = 0
for afterMarket in partData.afterMarke {
let afm = AfterMarketView()
afm.bottomPartLbl.text = partData.afterMarket![0].partNo
afm.bottomDesLbl.text = partData.afterMarket![0].description
afm.bottomPriceLbl.text = partData.afterMarket![0].price
afm.frmae = CGFrame(0, normalCellSize + afmNormalHight * currentCount, cell.frame.size.width, afmNormalHight)
currentCount++
cell.addSubview(afm)
}
i will build a UICollectionView with sections.
The sections are based on the return value from json.category.
the json format is like:
[{"id":"1",
"name":"Apple",
"category":"Fruits"},
{"id":"2",
"name":"Pie",
"category":"Fruits"},
{"id":"3",
"name":"Tomato",
"category":"Vegetable"}]
I need a array filter hat the array is something like: (for sectionsItems and sectionNames)
CategorieNames[STRING] = ["Fruits","Vegetable"] // the section names from json.category
Fruits = [STRING] = ["Apple","Pie"]
Vegetables = [STRING] = ["Tomato"]
Categories.append[Fruits]
Categories.append[Vegetables]
Categories[[STRING]] = [[Fruits],[Vegetable]]
Try bellow code.
let arrData = [["id": "1",
"name": "Apple",
"category": "Fruit"],
["id": "2",
"name": "Pie",
"category": "Fruit"],
["id": "3",
"name": "Tomato",
"category": "Vegetable"]]
let categorieNames = Array(Set(arrData.map({$0["category"]!})))
var arrResult:[[String]] = []
for i in 0..<categorieNames.count {
let categories = arrData.filter({$0["category"] == categorieNames[i]}).map({$0["name"]!})
arrResult.append(categories)
}
print("result : \(arrResult)")
result : [["Apple", "Pie"], ["Tomato"]]
you can do it as follows:
let arrData = [["id": "1",
"name": "Apple",
"category": "Fruit"],
["id": "2",
"name": "Pie",
"category": "Fruit"],
["id": "3",
"name": "Tomato",
"category": "Vegetable"]]
var categorys = [[String]]()
var fruits = [String]()
var vegetable = [String]()
for data in arrData {
if let category = data["category"] {
if category == "Fruit"{
if let aFruit = data["name"] {
fruits.append(aFruit)
}
}
else if category == "Vegetable" {
if let aVeggeie = data["name"] {
vegetable.append(aVeggeie)
}
}
}
}
categorys.append(fruits)
categorys.append(vegetable)
I have a JSON file I call from the internet
{
"Editions": [
{
"Version": "November",
"Articles": [
{
"title": "hello",
"subheading": "Article 1",
"content": "stuff",
"author": "John Smith",
"authorDescription": "Author",
"image": "pic1.jpg"
},
{
"title": "article2",
"subheading": "Article 2",
"content": "stuff2",
"author": "first name last name",
"authorDescription": "Author",
"image": ""
},
{
"title": "article3",
"subheading": "Article 3",
"content": "stuff3",
"author": "Callum West",
"authorDescription": "Author",
"image": ""
},
{
"title": "Article 4",
"subheading": "Article 4",
"content": "stuff 4",
"author": "tom C",
"authorDescription": "Author",
"image": ""
}
]
},
{
"Version": "October",
"Articles": [
{
"title": "article 1",
"subheading": "Article1",
"content": "stuff1.1",
"author": "Tom",
"authorDescription": "Author",
"image": ""
},
{
"title": "article2",
"subheading": "Article 2",
"content": "stuff2.1",
"author": "Sam",
"authorDescription": "Author",
"image": ""
},
{
"title": "article3",
"subheading": "Article 3",
"content": "stuff3.1",
"author": "TomC",
"authorDescription": "Author and Editor",
"image": ""
},
{
"title": "article 4",
"subheading": "Article 4",
"content": "stuff4.1",
"author": "brad name",
"authorDescription": "Author",
"image": ""
},
{
"title": "article5",
"subheading": "Article 5",
"content": "stuff5.1",
"author": "chris evuan",
"authorDescription": "Author",
"image": ""
},
{
"title": "article6",
"subheading": "Article 6",
"content": "stuff6.1",
"author": "Jo",
"authorDescription": "Author",
"image": ""
},
{
"title": "article7",
"subheading": "Article7",
"content": "stuff7.1",
"author": "Tom Hall",
"authorDescription": "Author",
"image": ""
}
]
}
]
}
On my first view controller I pull out the editions version with the following code
func loaddata(){
Alamofire.request(.GET, "my JSON url")
.responseJSON { response in
//get json from response data
//print (response.data)
let json = JSON(data: response.data!)
//print(json)
//for loop over json and write all article titles articles array
for (key, subJson) in json["Editions"] {
let version = subJson["Version"].string
let stuff = Edition(Version: version!)
// print(stuff)
self.editions.append(stuff!)
}
// let x = self.editions[0].Version
// print ("\(x)")
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
I then use a segue to pass the version clicked into my second view controller
Once done this on my second view controller I can print out the string of the version, in the view did load
let worked = pleasework as String!
//print("\(worked)")
I then want to use this string to traverse the Json and pull out the correlating content
So I call the function and pass it through
loaddata("\(worked)")
Here is the load data function
func loaddata(verionTitle: String){
Alamofire.request(.GET, "my JSON url")
.responseJSON { response in
//get json from response data
let json = JSON(data: response.data!)
// print(json)
//for loop over json and write all article titles articles array
// print("\(verionTitle)")
for (key, subJson) in json["Editions"][0]["Articles"]{
// print(subJson)
//let versionmuted = version as String!
//print("\(version)")
//if verionTitle =
//if version == verionTitle{
//print("The month is \(version)")
let author = subJson["title"].string
//print("\(author)")
let subheading = subJson["subheading"].string
let content = subJson["content"].string
let Author = subJson["author"].string
//let image = subJson["image"].string
let stuff = Article(name: author!, subheading: subheading!, content: content!, author: Author!)
self.articles.append(stuff!)
}
//end iff
//if let content = subJson["content"].string {
// self.Content.append(content)
//}
//end for
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}
I am struggling with looping over the JSON and only pulling out the articles relevant to the version, I am using the swiftyjson library
The current function obviously prints out all the articles in Editions[0]
However can i loop through all of Editions and use the string to only print Articles under that version
For example
for (key, subJson) in json["Editions"][0]["Version"] = veriontitle??{
//do stuff
}
Hope I explained myself well, hoping you can help
func loaddata(verionTitle: String){
Alamofire.request(.GET, "your json")
.responseJSON { response in
//get json from response data
let json = JSON(data: response.data!)
//print(json)
//start looping function pass through identifer from month, i've set October to 1 and so forth
func looping(Number: Int){
for (key, subJson) in json["Editions"][Number]["Articles"]{
let author = subJson["title"].string
//print("\(author)")
let subheading = subJson["subheading"].string
let content = subJson["content"].string
let Author = subJson["author"].string
let Image = subJson["image"].string
let stuff = Article(name: author!, subheading: subheading!, content: content!, author: Author!, image: Image!)
self.articles.append(stuff!)
//end loop
}
//end looping
}
//Get Version Titles, here is where I assign months to a number releavnt to where they are in the json
switch verionTitle{
case "November":
looping(0)
case "October":
looping(1)
case "December":
looping(2)
default:
print("no month")
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
}
}