【问题标题】:Parsing a JsonObject in Swift 4 from an URL从 URL 解析 Swift 4 中的 JsonObject
【发布时间】:2018-02-12 21:46:23
【问题描述】:

对我来说,这似乎是一项非常简单的任务,但即使经过大量研究和尝试,我也无法让它发挥作用......

例如,我有这个 URL,据我了解,这是 JSONObject 的 api?!

http://api.geekdo.com/api/images?ajax=1&gallery=all&nosession=1&objectid=127023&objecttype=thing&pageid=357&showcount=1&size=thumb&sort=recent

如果我在浏览器中打开此链接,我会得到以下结果:

{"images":[{"imageid":"1567153","imageurl_lg":"https://cf.geekdo-images.com/images/pic1567153_lg.jpg","name":null,"caption “:“白色的 力量 瓦片","numrecommend":"6","numcmets":"0","user":{"username":"manosdowns","avatar":"1","avatarfile":"avatar_id33829.jpg"} ,"imageurl":"https://cf.geekdo-images.com/6fCr14v025ZKYhXRMnbhYR16Ta8=/fit-in/200x150/pic1567153.jpg"}],"config":{"sorttypes":[{"type":" hot","name":"Hot"},{"type":"recent","name":"Recent"}],"numitems":402,"endpage":402,"galleries":[{" type":"all","name":"All"},{"type":"game","name":"Game"},{"type":"people","name":"People" },{"type":"creative","name":"Creative"}],"categories":[{"type":"","name":"All"},{"type":"BoxFront ","name":"BoxFront"},{"type":"BoxBack","name":"BoxBack"},{"type":"Components","name":"Components"},{"type ":"自定义","name":"自定义"},{"type":"播放","name":"播放"},{"type":"Miscellaneous","name":"Miscellaneous"} ,{"type":"Mature","name":"Mature"},{"type":"uncat","name":"Uncategorized"}],"licensefilters":[{"type":"" ,"name":"Any"},{"type":"reuse","name":"复制 允许"},{"type":"commercial","name":"商业用途 允许"},{"type":"modify","name":"修改 允许"}],"datefilters":[{"value":"alltime","name":"All 时间"},{"value":"today","name":"Today"},{"value":"twodays","name":"两个 天数"},{"value":"last7","name":"最后 7 个 天数"},{"value":"last30","name":"最近 30 Days"},{"value":"year","name":"Last 365 Days"}],"filters":[{"name":"Licenses","listname":"licensefilters","type":"licensefilter"},{"name":"Category","listname":" categories","type":"tag"},{"name":"Gallery","listname":"gallery","type":"gallery"}]}}

现在我的第一次尝试是用我解析主页的方式来解析这个链接:

    guard let myURL = URL(string: link) else {                                                 >             print("Error: \(link) doesn't seem to be a valid URL")
        return
    }

    do {
        link = try String(contentsOf: myURL, encoding: .ascii)
    } catch let error {
        print("Error: \(error)")
    }

但这不起作用,因为我现在明白这是因为这是 JSON 编码的?!

我搜索了解析 JSON 并找到了一些关于编码和解码的解释,但我的问题是,在所有给出的示例中,解释都是从已经“拥有”JsonObject 的内容开始的。 我的问题是我可以在浏览器中读取 URL 的内容,但我需要 Xcode 本身中的 URL 的内容,所以我可以解析它?!

所以在我的具体情况下,我只需要“imageurl_lg”的内容

...如果我可以在 Xcode 中显示我可以在浏览器中看到的内容,我会知道该怎么做 - 但是我如何将链接的内容获取到 Xcode 中?

作为参考,我还阅读了以下说明,但无法将它们应用于我的示例... https://www.raywenderlich.com/172145/encoding-decoding-and-serialization-in-swift-4

https://grokswift.com/json-swift-4/

还有一些,但他们没有帮助我......

【问题讨论】:

    标签: ios json swift api swift4


    【解决方案1】:

    您需要使用 URLSession 任务来执行此操作,之后您需要使用 JSONSerialization 在此示例中我返回一个 [String:Any] 的字典,您可以将其转换为您需要的任何模型

    使用此代码

    func fetchData(completion: @escaping ([String:Any]?, Error?) -> Void) {
        let url = URL(string: "http://api.geekdo.com/api/images?ajax=1&gallery=all&nosession=1&objectid=127023&objecttype=thing&pageid=357&showcount=1&size=thumb&sort=recent")!
    
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            guard let data = data else { return }
            do {
                if let array = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String:Any]{
                    completion(array, nil)
                }
            } catch {
                print(error)
                completion(nil, error)
            }
        }
        task.resume()
    }
    

    如何使用

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        fetchData { (dict, error) in
            debugPrint(dict)
        }
    }
    

    打印结果日志

    Optional(["config": {
        categories =     (
                    {
                name = All;
                type = "";
            },
                    {
                name = BoxFront;
                type = BoxFront;
            },
                    {
                name = BoxBack;
                type = BoxBack;
            },
                    {
                name = Components;
                type = Components;
            },
                    {
                name = Customized;
                type = Customized;
            },
                    {
                name = Play;
                type = Play;
            },
                    {
                name = Miscellaneous;
                type = Miscellaneous;
            },
                    {
                name = Mature;
                type = Mature;
            },
                    {
                name = Uncategorized;
                type = uncat;
            }
        );
        datefilters =     (
                    {
                name = "All Time";
                value = alltime;
            },
                    {
                name = Today;
                value = today;
            },
                    {
                name = "Two Days";
                value = twodays;
            },
                    {
                name = "Last 7 Days";
                value = last7;
            },
                    {
                name = "Last 30 Days";
                value = last30;
            },
                    {
                name = "Last 365 Days";
                value = year;
            }
        );
        endpage = 402;
        filters =     (
                    {
                listname = licensefilters;
                name = Licenses;
                type = licensefilter;
            },
                    {
                listname = categories;
                name = Category;
                type = tag;
            },
                    {
                listname = galleries;
                name = Gallery;
                type = gallery;
            }
        );
        galleries =     (
                    {
                name = All;
                type = all;
            },
                    {
                name = Game;
                type = game;
            },
                    {
                name = People;
                type = people;
            },
                    {
                name = Creative;
                type = creative;
            }
        );
        licensefilters =     (
                    {
                name = Any;
                type = "";
            },
                    {
                name = "Copying allowed";
                type = reuse;
            },
                    {
                name = "Commercial use allowed";
                type = commercial;
            },
                    {
                name = "Modification allowed";
                type = modify;
            }
        );
        numitems = 402;
        sorttypes =     (
                    {
                name = Hot;
                type = hot;
            },
                    {
                name = Recent;
                type = recent;
            }
        ); }, "images": <__NSSingleObjectArrayI 0x600000010710>( {
        caption = "White power tiles";
        imageid = 1567153;
        imageurl = "https://cf.geekdo-images.com/6fCr14v025ZKYhXRMnbhYR16Ta8=/fit-in/200x150/pic1567153.jpg";
        "imageurl_lg" = "https://cf.geekdo-images.com/images/pic1567153_lg.jpg";
        name = "<null>";
        numcomments = 0;
        numrecommend = 6;
        user =     {
            avatar = 1;
            avatarfile = "avatar_id33829.jpg";
            username = manosdowns;
        }; } ) ])
    

    更新修复“App Transport Security 已阻止明文”错误

    调整您的 info.plist

    【讨论】:

    • 谢谢,但现在我收到此错误:App Transport Security 已阻止明文 HTTP (http://) 资源加载,因为它不安全。可以通过应用程序的 Info.plist 文件配置临时例外。无法开始加载任务 .,因为它不符合 ATS 策略任务 . 完成并出现错误 - 代码: -1022
    • @MakiCodes 在你的 info.plist 中添加这些键检查我更新的答案
    • @MakiCodes 如果您需要进一步的帮助,请告诉我
    • 没关系,将链接更改为“https”就足够了。一个大大的“谢谢”!
    【解决方案2】:

    这就是游乐场给我的。

    import UIKit
    
    var str = "Hello, playground"
    
    func makeGetCall() {
        guard let myURL = URL(string: "http://api.geekdo.com/api/images?ajax=1&gallery=all&nosession=1&objectid=127023&objecttype=thing&pageid=357&showcount=1&size=thumb&sort=recent") else {
            print("Error: \(link) doesn't seem to be a valid URL")
            return
        }
    
        do {
            var content = try String(contentsOf: myURL, encoding: .ascii)
            print("Content: \(content)")
        } catch let error {
            print("Error: \(error)")
        }
    }
    makeGetCall()
    

    打印

    【讨论】:

    • 请不要推荐像String(contentsOf这样的同步方法。方法不合适。
    • 这不是建议,只是对 OP 自己的答案的简单更正。我在上面看到了更好的答案,所以我不需要发布更多内容。
    • @Gihan 谢谢你!我知道同步方法不是首选方法,但是您按照我的要求回答了我的问题! (我可能也需要实施您的解决方案!)
    • 没问题,在你学习的时候跟上好的做法。而且您可能想要支持@einier 的答案,因为它非常详细并且会帮助您。干杯
    猜你喜欢
    • 2015-03-18
    • 2021-06-12
    • 1970-01-01
    • 2015-09-14
    • 2019-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多