美文网首页
Thinking in Swift 系列文章翻译1

Thinking in Swift 系列文章翻译1

作者: 你weixiao的时候很美 | 来源:发表于2018-04-11 17:08 被阅读16次
    第一篇:名叫拯救小马🐴

    这里是原文地址 原文链接

    本系列一共4篇,讲oc与swift编程的差异的。

    本篇是关于 可选值optionals, 强制展开 forced-unwrapped optionals,非强制展开 guard , if let等的讨论。

    1.Objc code

    首先看一段OC的代码, 就是解析json,然后转换为model

    @interface ListItem : NSObject
    @property(strong) UIImage* icon;
    @property(strong) NSString* title;
    @property(strong) NSURL* url;
    @end
    
    @implementation ListItem
    +(NSArray*)listItemsFromJSONData:(NSData*)jsonData {
        NSArray* itemsDescriptors = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
        
        NSMutableArray* items = [NSMutableArray new];
        for (NSDictionary* itemDesc in itemsDescriptors) {
            ListItem* item = [ListItem new];
            item.icon = [UIImage imageNamed:itemDesc[@"icon"]];
            item.title = itemDesc[@"title"];
            item.url = [NSURL URLWithString:itemDesc[@"url"]];
            [items addObject:item];
        }
        return [items copy];
    }
    @end
    
    2. 从oc直接翻译成swift代码
    class ListItem {
        var icon: UIImage?
        var title: String = ""
        var url: NSURL!
        
        static func listItemsFromJSONData(jsonData: NSData?) -> NSArray {
            let jsonItems: NSArray = try! NSJSONSerialization.JSONObjectWithData(jsonData!, options: []) as! NSArray
            let items: NSMutableArray = NSMutableArray()
            for itemDesc in jsonItems {
                let item: ListItem = ListItem()
                item.icon = UIImage(named: itemDesc["icon"] as! String)
                item.title = itemDesc["title"] as! String
                item.url = NSURL(string: itemDesc["url"] as! String)!
                items.addObject(item)
            }
            return items.copy() as! NSArray
        }
    }
    
    3. 分析问题

    新手把强制解析用在各个地方。 value! 还有 value as! String 还有 try!等。 当值为nil的时候,会直接crash。
    Optionals 可选值是我们的朋友。当我们写oc的时候,我们经常忘记处理这种情况。但是,我们用swift的时候,应该去可选值等处理值为nil的情况。

    You should never force-unwrap a value, except when you really know what you’re doing. Keep in mind that every time you add a ! just to please the compiler, you’re killing a pony 🐴.
    你不应该使用! 除非你真的知道你在做什么。 记住每当你用一个 ! 去讨好编译器,你在杀死一只小马🐴。

    4. 如何处理这种情况

    我们应该如何做去避免到处使用 !

    • 使用可选绑定 if let x = optional { 使用x }
    • 使用 as? 代替 as!, 如果转换失败会返回nil
    • 使用 try?代替 try! 如果执行失败返回nil。

    所以,代替! 后的代码如下:

    class ListItem {
        var icon: UIImage?
        var title: String = ""
        var url: NSURL!
        
        static func listItemsFromJSONData(jsonData: NSData?) -> NSArray {
            if let nonNilJsonData = jsonData {
                if let jsonItems: NSArray = (try? NSJSONSerialization.JSONObjectWithData(nonNilJsonData, options: [])) as? NSArray {
                    let items: NSMutableArray = NSMutableArray()
                    for itemDesc in jsonItems {
                        let item: ListItem = ListItem()
                        if let icon = itemDesc["icon"] as? String {
                            item.icon = UIImage(named: icon)
                        }
                        if let title = itemDesc["title"] as? String {
                            item.title = title
                        }
                        if let urlString = itemDesc["url"] as? String {
                            if let url = NSURL(string: urlString) {
                                item.url = url
                            }
                        }
                        items.addObject(item)
                    }
                    return items.copy() as! NSArray
                }
            }
            return [] // In case something failed above
        }
    }
    
    5. 大括号金字塔

    如果到处使用if let 来解包可选值, 会造成大括号金字塔。就是逻辑嵌套过多。
    有一些替代的方式可以解决这种情况

    • 一些情况下可以使用 if let x= opt1,y= opt2 来代替两个if let嵌套
    • 可以使用guard 来代替 if let 。guard可以判断空值, 可以类型等,让我们预先做处理。
    class ListItem {
        var icon: UIImage?
        var title: String = ""
        var url: NSURL!
        
        static func listItemsFromJSONData(jsonData: NSData?) -> [ListItem] {
            guard let nonNilJsonData = jsonData,
                let json = try? NSJSONSerialization.JSONObjectWithData(nonNilJsonData, options: []),
                let jsonItems = json as? Array<NSDictionary>
                else {
                    // If we failed to unserialize the JSON
                    // or that JSON wasn't an Array of NSDictionaries,
                    // then bail early with an empty array
                   //就是guard 让我们预先对数据空,或者正确的情况做判断和处理。
                    return []
            }
            
            var items = [ListItem]()     // 用swift的写法来代替oc
            for itemDesc in jsonItems {
                let item = ListItem()
                if let icon = itemDesc["icon"] as? String {
                    item.icon = UIImage(named: icon)
                }
                if let title = itemDesc["title"] as? String {
                    item.title = title
                }
                if let urlString = itemDesc["url"] as? String, let url = NSURL(string: urlString) {
                    item.url = url
                }
                items.append(item)
            }
            return items
        }
    }
    

    guard 非常好用,因为,我们可以在函数开始的时候,预先检查 数据是否合法,在接下来的code中就不需要担心这些检查问题。

    6. swift比oc繁琐?

    上边的代码看起来是这样,swift比oc代码量更多。但是这只是因为oc没有做很多安全检查。oc代码可能在很多情况下崩溃比如:1.json不合法,2.json中数据类型不对等等。在oc中,我们忘记去处理这些情况。swift强制我们处理这些情况。

    7. 结论

    swift是按照更安全的理念被设计的,所以不要通过使用! 强制解包的方式来处理 可选值。如果你发现!, 你需要想想是否哪里出了错。

    小note
    // 1. 使用try? 的时候, 如果你不关心是什么原因导致的nil,可以直接用try?,如果你想要知道为何会返回nil,最好使用 do { try... } catch { }
    //2. 在最后一段代码中,保留了一个 ! 是 return items.copy() as! NSArray。 一些情况下,使用!是可以的,如果你真的真的知道值不是空的或者类型确定。

    相关文章

      网友评论

          本文标题:Thinking in Swift 系列文章翻译1

          本文链接:https://www.haomeiwen.com/subject/odqzhftx.html