Swift 编程思路的变化

今天看到这篇文章,才发现之前那次尝试着用 Swift 写代码时犯了一个多大的错误。

上次是在做优优育儿时,有一个新功能非常简单,就是一个单纯的列表页,所以尝试着用 Swift 进行了实现。而我当时正是像文章中写的那样,只是把之前 Objective-C 的写法按照 Swift 的语法进行了变化,然后相信了 Xcode 的代码更正提示,结果虽然可以正常运行,但代码里全是 exclamation mark。

阅读了这个系列的文章,发现 Swift 的确是个现代化的语言。虽然凭借传统语言的知识可以很容易地入手,但它所带来的不仅仅是语法的改变,更多的是编程思路的变化。

下面我将分别展示三段代码,功能是从 JSON 串中得到一个 Article 对象的数组。第一段是用 Objective-C 编写的代码,这也是我写这种功能的标准形式。第二段是按照传统思路编写的 Swift 代码,是应该避免的。第三段是用正确的思路编写的 Swift 代码。

第一段代码

ArticleObject.h
1
2
3
@interface ArticleObject : NSObject
+ (NSArray*)articleArrayWithJSONData:(NSData*)data;
@end
ArticleObject.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#import "ArticleObject.h"
@interface ArticleObject()
@property (strong, nonatomic) NSString *objectID;
@property (strong, nonatomic) NSString *title;
@property (strong, nonatomic) NSURL *url;
@end
@implementation ArticleObject
+ (NSArray*)articleArrayWithJSONData:(NSData*)data {
NSArray *arrData = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSMutableArray *arrArticle = [[NSMutableArray alloc]init];
for (NSDictionary *dictItem in arrData) {
ArticleObject *articleObj = [[ArticleObject alloc]initWithDictionary:dictItem];
[arrArticle addObject:articleObj];
}
return arrArticle;
}
- (instancetype)initWithDictionary:(NSDictionary*)dict {
if (self = [super init]) {
[self setWithDictionary:dict];
}
return self;
}
- (void)setWithDictionary:(NSDictionary*)dict {
[self setObjectID:dict[@"id"]];
[self setTitle:dict[@"title"]];
[self setUrl:[NSURL URLWithString:dict[@"url"]]];
}
@end

第二段代码

可以看到,这段代码完全就是上面代码的 Swift 版,很容易理解,但里面有很多的惊叹号。至于为什么这样做非常不好,可以参见最开头提到的文章。

ArticleObject.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ArticleObject: NSObject {
var objectID: String = ""
var title: String = ""
var url: NSURL!
static func articleArrayWithJSONData(data: NSData) -> NSArray {
let arrData: NSArray = try! NSJSONSerialization.JSONObjectWithData(data, options: []) as! NSArray
let arrArticle: NSMutableArray = NSMutableArray()
for dictItem in arrData {
let articleObj : ArticleObject = ArticleObject()
articleObj.setWithDictionary(dictItem as! NSDictionary)
arrArticle.addObject(articleObj)
}
return arrArticle
}
func setWithDictionary(dict: NSDictionary) {
self.objectID = dict["id"] as! String
self.title = dict["title"] as! String
self.url = NSURL(string: dict["url"] as! String)
}
}

第三段代码

这里面就有很多 Swift 的新东西了,比如 guard let, if let, flatMap 等。虽然代码好像更长了,也不那么易懂了,但这才是更安全可靠的代码。

ArticleObject.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class ArticleObject {
var objectID: String
var title: String
var url: NSURL
static func articleArrayWithJSONData(data: NSData) -> [ArticleObject] {
guard let jsonData = try? NSJSONSerialization.JSONObjectWithData(data, options: []),
let arrData = jsonData as? Array<Dictionary<String,AnyObject>>
else {return[]}
return arrData.flatMap{(dictItem: Dictionary<String,AnyObject>) -> ArticleObject? in
if let articleObj: ArticleObject = ArticleObject(dictionary: dictItem) {
return articleObj
} else {
return nil;
}
}
}
init?(dictionary: [String:AnyObject]) {
guard let objectID = dictionary["id"] as? String,
let title = dictionary["title"] as? String,
let urlString = dictionary["url"] as? String,
let url = NSURL(string: urlString)
else {return nil}
self.objectID = objectID;
self.title = title;
self.url = url;
}
func setData(withDictionary: NSDictionary) {
guard let objectID = withDictionary["id"] as? String,
let title = withDictionary["title"] as? String,
let urlString = withDictionary["url"] as? String,
let url = NSURL(string: urlString)
else {return}
self.objectID = objectID;
self.title = title;
self.url = url;
}
}