变更记录

序号 录入时间 录入人 备注
1 2015-03-03 Alfred Jiang -
2 2015-12-22 Alfred Jiang -
2 2016-02-01 Alfred Jiang -

方案名称

语法 - 使用字面量

关键字

语法 \ 字面量 \ 字面值

需求场景

  1. 提高代码可读性

参考链接

  1. IOS使用字面值
  2. Swifter - 字面量转换
  3. GitHub - Literally
  4. Clang 3.9 documentation - Objective-C Literals

详细内容

#####1. Swift 解决方案

#####NSString

1
let aString = "Hello"

#####Number

1
2
let aNumber : NSNumber = 3
let aBool : NSNumber = true

#####NSArray

1
let anArray = [1,2,3]

#####Dictionary

1
let aDictionary = ["key1": "value1", "key2": "value2"]

Swift 为我们提供了一组非常有意思的接口,用来将字面量转换为特定的类型。对于那些实现了字面量转换接口的类型,在提供字面量赋值的时候,就可以简单地按照接口方法中定义的规则“无缝对应”地转换为这些类型。这些接口包括了各个原生的字面量,它们是:

ArrayLiteralConvertible

BooleanLiteralConvertible

CharacterLiteralConvertible

DictionaryLiteralConvertible

ExtendedGraphemeClusterLiteralConvertible

FloatLiteralConvertible

NilLiteralConvertible

IntegerLiteralConvertible

StringLiteralConvertible

StringInterpolationConvertible

用法举例:

通常通过 NSString 定义一个 NSURL 的方法如下

1
let url = NSURL(string: "http://swifter.tips")

使用 StringLiteralConvertible 构造一个 NSURL 的 extension

1
2
3
4
5
6
7
8
9
10
11
12
13
extension NSURL: StringLiteralConvertible {
public class func
convertFromStringLiteral(value: String) -> Self
{
return self(string: value)
}

public class func
convertFromExtendedGraphemeClusterLiteral(value: String) -> Self
{
return self(string: value)
}
}

那么我们现在可以直接使用如下方式直接赋值 NSString 生成 NSURL

1
let url: NSURL = "http://swifter.tips"

#####2. Objective-C 解决方案

#####NSString

1
2
3
4
5
NSString *str = [[NSString alloc] initWithFormat:@"%@",@"Hello World"];

//---->字面值如下

NSString *str = @"Hello World";

#####Number

1
2
3
4
5
6
7
8
9
NSNumber *someNumber = [NSNumber numberWithInt:1];

//---->字面值如下

NSNumber *intNumber = @1;
NSNumber *floatNumber = @2.5f;
NSNumber *doubleNumber = @3.14159;
NSNumber *boolNumber = @YES;
NSNumber *charNumber = @'a';

#####NSArray

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
NSArray *animals =[NSArray arrayWithObjects:@"cat", @"dog", @"mouse", @"badger", nil];

//---->字面值如下

NSArray *animals = @[@"cat", @"dog", @"mouse", @"badger"];

NSString *dog = [animals objectAtIndex:1];

//---->通过字面值取数据

NSString *dog = animals[1];

//可变的话可以直接设置新值
[mutableArray replaceObjectAtIndex:1 withObject:@"dog"];

//---->字面值设置值

mutableArray[1] = @"dog";


NSString *str1;
NSString *str2 = @"1";
NSString *str3 = @"1";

//插入空数据会抛出异常
NSArray *arr = @[str1,str2,str3];

//reason: '*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'

//这种方式不会抛异常,但是数组会收到第一个nil就终止了。所以采用字面值形式会得到错误提示。
NSArray *arr = [NSArray arrayWithObjects:str1,str2,str3, nil];
NSLog(@"arr.count=%d",arr.count); //0
NSLog(@"arr.first=%@",arr.firstObject); //null

#####Dictionary

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
NSDictionary *personData =[NSDictionary dictionaryWithObjectsAndKeys:@"Kevin", @"firstName",@"Jin", @"lastName",[NSNumber numberWithInt:25], @"age", nil];

//---->字面值如下

NSDictionary *personData = @{@"firstName" : @"Kevin",@"lastName" : @"Jin", @"age" : @25};


NSString *str1;
NSString *str2 = @"1";
NSString *str3 = @"1";
//和数组一样,value不能有nil ,否则就会抛出异常。
NSDictionary *dic =@{@"str1":str1,@"str2":str2,@"str3":str3};

//reason: '*** -[__NSPlaceholderDictionary initWithObjects:forKeys:count:]: attempt to insert nil object from objects[0]'

//不会提示你错误
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:str1,@"str2",str2,@"str2",str3,@"str3", nil];
NSLog(@"dic.count=%d",dic.count); //0

//取值
NSString *lastName = [personData objectForKey:@"lastName"];

//---->字面值取值

NSString *lastName = personData[@"lastName"];

//可变的话可以这样设置新值
[mutableDictionary setObject:@"Galloway" forKey:@"lastName"];

//---->字面值设置值

mutableDictionary[@"lastName"] = @"Galloway";

效果图

(无)

备注

访问的时候数组采用下标方式,字典直接通过 Key 来取值,需要注意的就是数组和字典中不能插入 nil,否则会抛出异常。

字面量语法可以读写 mutable 类型的对象,但通过字面量语法创建的对象是非 mutable 的。如果需要将非 mutable 类的字面量对象变更为 mutable 类型,可以使用 mutableCopy 方法。

1
NSMutableArray *mutable = [@[@1, @2, @3, @4, @5] mutableCopy]; 

自定义的字面量语法对象的子类不支持字面量语法。

以下为Github上的常用 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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// Literally.swift
//
// Copyright (c) 2014 Mattt Thompson (http://mattt.me)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// MARK: - Foundation -

import Foundation

// MARK: NSCharacterSet

extension NSCharacterSet: ArrayLiteralConvertible {
public class func convertFromArrayLiteral(characters: Character...) -> Self {
return self(charactersInString: join("", characters.map({String($0)})))
}
}

extension NSCharacterSet: StringLiteralConvertible {
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

public class func convertFromExtendedGraphemeClusterLiteral(value: StringLiteralType) -> Self {
return self(charactersInString: value)
}

public class func convertFromStringLiteral(value: StringLiteralType) -> Self {
return self(charactersInString: value)
}
}

// MARK: NSExpression

extension NSExpression: StringLiteralConvertible {
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

public class func convertFromExtendedGraphemeClusterLiteral(value: StringLiteralType) -> Self {
return self(format: value, argumentArray: [])
}

public class func convertFromStringLiteral(value: StringLiteralType) -> Self {
return self(format: value, argumentArray: [])
}
}

// MARK: NSIndexPath

extension NSIndexPath: ArrayLiteralConvertible {
public class func convertFromArrayLiteral(indexes: Int...) -> Self {
return self(indexes: indexes, length: indexes.count)
}
}

// MARK: NSIndexSet

extension NSIndexSet: ArrayLiteralConvertible {
public class func convertFromArrayLiteral(indexes: Int...) -> Self {
var mutableIndexSet = NSMutableIndexSet()
for index in indexes {
mutableIndexSet.addIndex(index)
}

return self(indexSet: mutableIndexSet)
}
}

// MARK: NSNull

extension NSNull: NilLiteralConvertible {
public class func convertFromNilLiteral() -> Self {
return self()
}
}

// MARK: NSOrderedSet

extension NSOrderedSet: ArrayLiteralConvertible {
public class func convertFromArrayLiteral(elements: AnyObject...) -> Self {
return self(array: elements)
}
}

// MARK: NSPredicate

extension NSPredicate: StringLiteralConvertible {
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

public class func convertFromExtendedGraphemeClusterLiteral(value: StringLiteralType) -> Self {
return self(format: value, argumentArray: [])
}

public class func convertFromStringLiteral(value: StringLiteralType) -> Self {
return self(format: value, argumentArray: [])
}
}

// MARK: NSRegularExpression

extension NSRegularExpression: StringLiteralConvertible {
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

public class func convertFromExtendedGraphemeClusterLiteral(value: StringLiteralType) -> Self {
return self(pattern: value, options: nil, error: nil)
}

public class func convertFromStringLiteral(value: StringLiteralType) -> Self {
return self(pattern: value, options: nil, error: nil)
}
}

// MARK: NSScanner

extension NSScanner: StringLiteralConvertible {
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

public class func convertFromExtendedGraphemeClusterLiteral(value: StringLiteralType) -> Self {
return self(string: value)
}

public class func convertFromStringLiteral(value: StringLiteralType) -> Self {
return self(string: value)
}
}

// MARK: NSSet

extension NSSet: ArrayLiteralConvertible {
public class func convertFromArrayLiteral(elements: AnyObject...) -> Self {
return self(array: elements)
}
}

// MARK: NSTimeZone

extension NSTimeZone: StringLiteralConvertible {
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

public class func convertFromExtendedGraphemeClusterLiteral(value: StringLiteralType) -> Self {
return self(name: value)
}

public class func convertFromStringLiteral(value: StringLiteralType) -> Self {
return self(name: value)
}
}

// MARK: NSURL

extension NSURL: StringLiteralConvertible {
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

public class func convertFromExtendedGraphemeClusterLiteral(value: StringLiteralType) -> Self {
return self(string: value)
}

public class func convertFromStringLiteral(value: StringLiteralType) -> Self {
return self(string: value)
}
}

// MARK: - UIKit -

#if os(iOS)

import UIKit

// MARK: UIColor

extension UIColor: IntegerLiteralConvertible {
public class func convertFromIntegerLiteral(value: IntegerLiteralType) -> Self {
let red = CGFloat((value & 0xFF0000) >> 16) / 255.0
let green = CGFloat((value & 0x00FF00) >> 8) / 255.0
let blue = CGFloat(value & 0x0000FF) / 255.0
let alpha = CGFloat(1.0)

return self(red: red, green: green, blue: blue, alpha: alpha)
}
}

// MARK: UIImage

extension UIImage: StringLiteralConvertible {
typealias ExtendedGraphemeClusterLiteralType = StringLiteralType

public class func convertFromExtendedGraphemeClusterLiteral(value: StringLiteralType) -> Self {
return self(named: value)
}

public class func convertFromStringLiteral(value: StringLiteralType) -> Self {
return self(named: value)
}
}

#endif

// MARK: - AppKit -

#if os(OSX)

import Cocoa

extension NSColor: IntegerLiteralConvertible {
public class func convertFromIntegerLiteral(value: IntegerLiteralType) -> Self {
let red = CGFloat((value & 0xFF0000) >> 16) / 255.0
let green = CGFloat((value & 0x00FF00) >> 8) / 255.0
let blue = CGFloat(value & 0x0000FF) / 255.0
let alpha = CGFloat(1.0)

return self(red: red, green: green, blue: blue, alpha: alpha)
}
}

#endif