[Résolu] Je patauge avec Alamofire

Hello à tous,

J’ai un soucis avec Alamofire, ou plutôt avec l’exploration d’un Json. Je commence à m’arracher les cheveux (déjà que j’en ai pas beaucoup… :rofl: )

En gros, voici la structure du Json :
{
“nbItems”:10,
“data”:[
{ “id”:1, “title”:“Mon titre”, “link”:“http://xxxx.fr” },
{ “id”:2, “title”:“Mon titre”, “link”:“http://xxxx.fr” },
{ “id”:3, “title”:“Mon titre”, “link”:“http://xxxx.fr” },
{ “id”:4, “title”:“Mon titre”, “link”:“http://xxxx.fr” },
{ “id”:5, “title”:“Mon titre”, “link”:“http://xxxx.fr” },
{ “id”:6, “title”:“Mon titre”, “link”:“http://xxxx.fr” },
{ “id”:7, “title”:“Mon titre”, “link”:“http://xxxx.fr” },
{ “id”:8, “title”:“Mon titre”, “link”:“http://xxxx.fr” },
{ “id”:9, “title”:“Mon titre”, “link”:“http://xxxx.fr” },
{ “id”:10, “title”:“Mon titre”, “link”:“http://xxxx.fr” }
]
}

Je regarde en boucle la video du cours iOS 3 (81 - “Remplir une UITableView avec des données du web”) mais je ne parvient à chercher les données que je souhaite dans ma boucle.

Comment récupérer “title” par exemple? Je ne vois comment imbriquer des clé/valeur dans d’autres clé/valeurs. C’est une histoire de syntaxe je présume.

        if let news = response.result.value as? [String:Any] {
            print(news["data"]) //ca fonctionne, je récupère le data du json (qui contient tous les articles), mais je ne peux pas aller plus loin dans l'arborescence 
            for data in news {
                print("------> \(data["data"]["title"]))")
            }
        }

HEEEEEEELP :disappointed_relieved:

A froid, sans réfléchir au sujet, tu devrais convertir ton data en un dictionnaire ou un tableau pour en extraire les informations.

Pour info, Swift 4 gère nativement le format Json, ce qui évite les bricolages de Swift 3 pour extraire les infos. Je présume que Maxime a dus parler de ça dans la version Swift 4 et iOS 11 de ses vidéos.

Il n’en a pas encore parlé dans le cours sur swift 4 :pensive:

@Samir en a parlé dans un autre post, avec un petit exemple en Swift 4 :

http://community.purplegiraffe.fr/t/astuce-swift-4-json/295

J’ai fouillé sur le net et je suis tombé là dessus : https://troz.net/2017/06/json-parsing-in-swift-4/

Ça rejoint le post de @Samir avec des exemples concrets mais je ne parvient pas l’utiliser dans mon cas, surement à cause des données avant que le tableau en lui même ne commence (nbItems et data).

J’ai fait ma structure comme ça:
struct News: Codable {
let nbItems: String
let data: Data
struct Data: Codable {
let title: String
}
}

Je ne parvient toujours pas à explorer les données :sob:

ou alors ca vient de là ?

let jsonDecoder = JSONDecoder()
let news = try? jsonDecoder.decode(Array<News>.self, from: jsonData)

news?.count
dump(news?.first)

Salut Didier,

La solution a ton problème s’appel codable-alamofire: https://github.com/Otbivnoe/CodableAlamofire car visiblement Alamofire n’est pas encore compatible avec la nouvelle fonctionnalité de swift 4.

Merci @Samir

Si j’ai bien compris, l’avantage d’Alamofire c’est que la récupération des données est asynchrone? Donc ca rend les applications plus fluides et charge les données quand elles sont prêtes?

Alors en fait Alamofire et avant tous une librairie qui simplifie grandement la gestion des “echanges reseaux classique”. Pour te rendre compte essaye de le faire via les librairie fournie par apple et tu verra que c’est horriblement long et chiant. Il faut savoir que Alamofire utilise uniquement les librairie apple.

En d’autre terme : Alamofire c’est la vie :slight_smile:

1 « J'aime »

Merci pour la définition @Samir :blush:
Par contre, je n’arrive pas à installer le pod que tu m’a indiqué …

# TODO: Remove this after all pods are converted to swift 4
def swift4_overrides
    pod 'Alamofire', git: 'https://github.com/Alamofire/Alamofire.git', branch: 'swift4'
end
target 'Test' do
  use_frameworks!
  swift4_overrides
  pod 'CodableAlamofire', :git => 'https://github.com/Otbivnoe/CodableAlamofire.git'
end

J’ai des erreurs de téléchargement d’Alamofire, mais il n’y a pas de branch swift4 dans Alamofire apparement sur GitHub.

Il y a quelque chose que je fais mal ?

Modifie simplement ton podfile comme ceci (sa marche pour moi):

target ‘myFirstApi’ do
use_frameworks!

pod ‘Alamofire’, '~> 4.4’
pod ‘CodableAlamofire’, :git => 'https://github.com/Otbivnoe/CodableAlamofire.git
end

Merci @Samir ! :wink: Je pensais qu’il fallait une version spéciale d’Alamofire alors j’ai pas osé.

Pas de soucis en tous cas n’hésite pas :slight_smile:

1 « J'aime »

C’est vraiment cool d’avoir une communauté qui ne râle pas a aider et qui donne de vraies explications! :+1:t2:

J’ai pu avancer à grands pas mais j’essaye maintenant de fusionner ça avec une class qui va gérer les articles des news que je souhaite afficher mais j’obtiens toujours une erreur :

Cannot convert value of type ‘News’ to expected argument type ‘[String : AnyObject]’

sur la ligne:
if let articleObject = Article(fromData: articleData) {

du code ci-dessous

func getNews() {
        struct News: Codable {
            var id:Int
            var title:String
            var abstract:String
            var content:String
            var link:URL
            var mainMedia: mainMedia
            struct mainMedia: Codable {
                var urlThumb: URL
            }
        }
        let url = URL(string: "http://xxxxxxxxxxxxxxxx.fr/api/news.json")!
        let decoder = JSONDecoder()
        decoder.dateDecodingStrategy = .secondsSince1970 // It is necessary for correct decoding. Timestamp -> Date.
        
        Alamofire.request(url).responseDecodableObject(keyPath: "data", decoder: decoder) { (response: DataResponse<[News]>) in
            if response.result.isSuccess {
                let rawArticleList = response.result.value
                for articleData in rawArticleList! {
                    if let articleObject = Article(fromData: articleData) {
                        self.arrayOfCellData.append(articleObject)
                    }
                }
                self.ui_tableView.reloadData()
            } else {
                print(response.result.error!)
            }
        }
    }

et ça c’est la class:

import Foundation
class Article {
    var id:Int
    var title:String
    var abstract:String
    var content:String
    var link:URL
    var image:String
    init?(fromData articleData:[String:AnyObject]) {
        guard let id = articleData["id"] as? Int,
                let title = articleData["title"] as? String,
                let abstract = articleData["abstract"] as? String,
                let content = articleData["content"] as? String,
                let link = articleData["link"] as? URL,
                let image = articleData["urlThumb"] as? String
            else {
                return nil
        }
        self.id = id
        self.title = title
        self.abstract = abstract
        self.content = content
        self.link = link
        self.image = image
    }
}

N’ayant jamais utilisé Alamofire je ne peux tester ton code. A ce que je comprend, tu récupères un tableau d’objets de type News, que tu tentes de convertir en objet de type Article.

Cela ne risque de pas fonctionner, si tu passe une variable de type News à une fonction s’attendant à recevoir une information de type [String:AnyObject], c’est à dire un dictionnaire …

Pour autant que je comprenne, Alamofire a déjà fait le travail de décryptage des données brutes, et te retourne une classe News prête à l’emploi.

Il y a une astuce pour connaître le type d’une variable avec Xcode. Il faut placer le curseur de la souris sur le nom de la variable et regarder dans le coin haut droit de l’écran. Vérifie, je parie que ta variable articleData est de type News.

Je pense que tu dois juste écrire une fonction pour créer un objet Article à partir d’un objet News.

J’ai réussi !!! merci 1000 fois ^^

2 « J'aime »

Même problème que toi @didier… je viens de passer le weekend la dessus mais je crois que je me suis perdu…

Comment as-tu solutionné ça ?

Hello @alexandre.cane

Content de savoir que je ne suis pas le seul finalement :wink:

Je t’avoue que ça remonte un peu et que je ne pourrais plus te dire quelle à été ma reflexion début Septembre :thinking:… mais ce que je peux te donner, c’est le code que j’utilise maintenant.

En gros, j’ai viré la class Article:

 func getNews() {
    struct News: Codable {
        var id:Int
        var title:String
        var abstract:String
        var content:String
        var fullLink:URL
        var mainMedia: mainMedia
        struct mainMedia: Codable {
            var urlThumb:String
        }
    }
    let url = URL(string: "http://xxxxxxxxxxxxxxxx.fr/api/news.json")!
    let decoder = JSONDecoder()
    decoder.dateDecodingStrategy = .secondsSince1970 // It is necessary for correct decoding. Timestamp -> Date.
    
    Alamofire.request(url).responseDecodableObject(keyPath: "data", decoder: decoder) { (response: DataResponse<[News]>) in
        let article = response.result.value
        if article != nil {
            for article in article! {
                let id = article.id
                let title = article.title
                let abstract = article.abstract
                let content = article.content
                let link = article.fullLink
                if let imageData: NSData = NSData(contentsOf: URL(string: article.mainMedia.urlThumb)!) {
                    let image = UIImage(data: imageData as Data)
                    self.arrayOfCellData.append(cellData(cell: id, id: id, title: title, abstract: abstract, content: content, link: link, image: image!))
                } else {
                    self.arrayOfCellData.append(cellData(cell: id, id: id, title: title, abstract: abstract, content: content, link: link, image: #imageLiteral(resourceName: "xxxxxxxxxxx LOGO 2017 [NOIR] 1000")))
                }
            }
        }
        self.ui_tableView.reloadData()
    }
}

Dans mon cas, tout est stocké dans un tableau. arrayOfCellData:[cellData] qui a cette structure :

struct cellData {
    let cell:Int
    let id:Int
    let title:String
    let abstract:String
    let content:String
    let link:URL
    let image:UIImage
}

Voila, j’espère que ça peut t’aider!

Merci beaucoup ! Problème réglé et notion assimiler. A bientôt

1 « J'aime »