【问题标题】:Ambiguous use of subscript?下标使用不明确?
【发布时间】:2016-09-11 12:33:51
【问题描述】:

我可以发出 Facebook SDK 图形请求来获得用户的喜欢,但我无法获取返回的值并将其中一个键存储在字符串数组中。该请求返回键/值的 NSDictionary。然后,使用objectForKey 我可以获得data 键,它返回我想要的:Facebook 上“喜欢”页面的 ID 和名称。

数据返回这样的元素:

{
        id = 486379781543416;
        name = "Star Wars Movies";
    },

我特别想要所有这些对象的“名称”并将它们放入数组[String]。我试图遍历对象,但出现错误ambiguous use of subscript。以下是相关代码:

request.startWithCompletionHandler{(connection:FBSDKGraphRequestConnection!, result:AnyObject!, error:NSError!) -> Void in
            let resultdict = result as! NSDictionary     
            let likes = resultdict.objectForKey("data") as! NSArray
            print("Found \(likes.count) likes")
            print(likes)

            for object in likes{

                let name = object["name"] as! String //error: ambiguous use of subsript
                print(name)
            }

        }

在做了一些研究之后,看起来问题出在 NSArray 上,我应该改用 Swift 数据类型。我尝试将其转换为 Swift 数组,但出现了不同的错误。

处理此错误的最佳方法是什么?

谢谢!

更新:这是 facebook API 请求返回的内容:

{
    data =     (
                {
            id = 111276025563005;
            name = "Star Wars (film)";
        },
                {
            id = 115061321839188;
            name = "Return of the Jedi";
        }
    );
    paging =     {
        cursors =         {
            after = MTE1MDYxMzIxODM5MTg4;
            before = Mjc0NzYzODk2MTg4NjY5;
        };
        next = "https://graph.facebook.com/v2.5/10155262562690368/likes?access_token=<redacted>";
    };
}

【问题讨论】:

    标签: ios arrays swift facebook swift2


    【解决方案1】:

    您应该始终尽可能使用原生 Swift 集合类型,因为 NSArrayNSDictionary 确实与类型无关,因此很容易触发“下标使用不明确”错误。

    您还需要避免强制向下转换,以防收到格式错误的数据或根本没有数据。使用guard 可以更优雅地处理这种情况,以防止崩溃。如果你的程序依赖于强制向下转换成功,因此应该崩溃——那么你总是可以在守卫中调用fatalError,并按顺序使用描述性错误消息帮助您调试问题。

    如果我正确理解您的数据结构,该请求会返回一个 AnyObject,它应该是一个 [String:AnyObject](任何对象的字符串字典)。在 "data" 键的情况下,AnyObject 值是 [[String:AnyObject]](任何对象的字符串字典数组)。

    因此,您需要分两个阶段进行投射。首先,在result 上使用条件向下转换将其转换为[String:AnyObject]。如果失败,则将执行守卫的 else 子句并返回代码。然后,您需要取出您的"data" 值(您的“喜欢”数组),并有条件地将其向下转换为[[String:AnyObject]]。这两个语句都将处理resultDictresultDict["data"] 成为nil 的可能性。

    guard let resultDict = result as? [String:AnyObject] else {return}
    guard let likes = resultDict["data"] as? [[String:AnyObject]] else {return}
    

    您可以将所需的任何错误处理逻辑放在这些语句的括号中,以处理结果字典不存在、格式错误或其中没有“喜欢”数组的情况。

    然后,您可以通过使用 flatMap 来获取“喜欢”名称的数组。

    let likeNames = likes.flatMap{$0["name"] as? String}
    

    这将创建一个包含每个字典的相似名称的数组——如果相似名称不存在或不是字符串,则不会添加它们。因为编译器确定知道likes[[String:AnyObject]]——在下标它的元素时没有歧义。

    如果您想要更通用的方法,例如您在问题中所做的,您可以在 for 循环中使用保护语句。

    for object in likes {
        guard let name = object["name"] as? String else {continue}
        print(name)
    }
    

    同样,您可以将任何您希望的错误处理放在守卫的括号中。

    【讨论】:

    • 非常感谢您提供的详细信息(可能是我在此站点上收到的最详细、最彻底的解释)。我开始了解您的目标(我对此还是比较陌生),但 resultDict 似乎没有返回任何带有guard let resultDict = result as? [String:[[String:AnyObject]]] else {return} 的结果。我在每一行都设置了断点,一旦它到达那一行,其余的代码就不会执行。我将使用 FBSDK 请求返回的整个输出更新问题,以便您查看结构
    • @james 好吧,results 字典值不是常量类型——我已经更新了我的答案来解决这个问题。基本上你需要投两次。一次将results 转换为[String:AnyObject],然后在获得"data" 值后,您可以将其从AnyObject 转换为[[String:AnyObject]]
    • 您更新的答案有效!十分感谢你的帮助。我肯定需要重新阅读其中的一些内容以了解发生了什么(我承认我对选角有点迷失)。我也从来不知道平面图。很有用!你有博客/网站吗?我很想继续向你学习 Swift。再次感谢!
    • @james 乐于助人!即使在最好的情况下,处理大数据结构也肯定会令人困惑——它通常总是有助于将其分解为更小的步骤(即从字典中获取一个值,对其进行强制转换,然后为它下标——每个步骤都在不同的行上)。不幸的是,我没有博客/网站(没有时间!)——但我确实密切关注 [swift] 标签,所以我一定会留意你未来的任何问题:) 你可以随时在 SO 聊天室 ping me 过来——尽管我可能无法立即回复。
    猜你喜欢
    • 2016-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多