美文网首页
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