关于String的思考

  • 一个String变量战胜多少内存?
  • 下面两个String变量,底层存储有什么不同?
    1
    2
    var str1 = "0123456789"
    var str2 = "0123456789ABCDEF"
  • 如果对String进行拼接操作,String变量的存储会发生什么变化?
    1
    2
    3
    4
    5
    str1.append("ABCDE")

    str1.append("F")

    str1.append("G")

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 字符串长度 <= 0xF(16位),字符串内容直接存放在str1变量的内存中
var str1 = "0123456789"

// 字符串长度 > 0xF,字符串内容存放在__TEXT.cstring中(常量区)
// 字符串的地址值信息存放在str2变量的后8个字节中
var str2 = "0123456789ABCDEF"


// 由于字符串长度 <= 0xF,所以字符串内容依然存放在str1变量的内存中
str1.append("ABCDE")
// 开辟堆空间
str1.append("F")

// 开辟堆空间
str2.append("G")

常规定义

  • Swift的字符串类型String,跟OC的NSString,在API设计上还是有较大差异
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 空字符串
    var emptyStr1 = ""
    var emptyStr2 = String()

    var str: String = "1"
    // 拼接,jack_rose
    str.append("_2")
    // 重载运算符 +
    str = str + "_3"
    // 重载运算符 +=
    str += "_4"
    // \()插值
    str = "\(str)_5"
    // 长度,9,1_2_3_4_5
    print(str.count)

    var str = "123456"
    print(str.hasPrefix("123")) // true
    print(str.hasSuffix("456")) // true

String的插入和删除

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var str = "1_2"
// 1_2_
str.insert("_", at: str.endIndex)
// 1_2_3_4
str.insert(contentsOf: "3_4", at: str.endIndex)
// 1666_2_3_4
str.insert(contentsOf: "666", at: str.index(after: str.startIndex))
// 1666_2_3_8884
str.insert(contentsOf: "888", at: str.index(before: str.endIndex))
// 1666hello_2_3_8884
str.insert(contentsOf: "hello", at: str.index(str.startIndex, offsetBy: 4))

// 666hello_2_3_8884
str.remove(at: str.firstIndex(of: "1")!)
// hello_2_3_8884
str.removeAll { $0 == "6" }
var range = str.index(str.endIndex, offsetBy: -4)..<str.index(before: str.endIndex)
// hello_2_3_4
str.removeSubrange(range)

SubSting

  • String可以通过下标、prefix、suffix等截取子串,子串类型不是String,而是Substring
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var str = "1_2_3_4_5"
    // 1_2
    var substr1 = str.prefix(3)
    // 4_5
    var substr2 = str.suffix(3)
    // 1_2
    var range = str.startIndex..<str.index(str.startIndex, offsetBy: 3)
    var substr3 = str[range]
    // 最初的String,1_2_3_4_5
    print(substr3.base)
    // Substring -> String
    var str2 = String(substr3)
  • Substring和它的base,共享字符串数据
  • Substring发生修改 或者 转为String时,会分配新的内存存储字符串数据

String与Character

1
2
3
4
5
6
for c in "jack" { // c是Character类型
print(c)
}
var str = "jack"
// c是Character类型
var c = str[str.startIndex]

String相关的协议

  • BidirectionalCollection 协议包含的部分内容
    • startIndex、endIndex 属性、index 方法
    • String、Array 都遵守了这个协议
  • RangeReplaceableCollection 协议包含的部分内容
    • append、insert、remove 方法
    • String、Array 都遵守了这个协议
  • Dictionary、Set 也有实现上述协议中声明的一些方法,只是并没有遵守上述协议

多行String

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
let str = """
1
"2"
3
'4'
"""
//输出格式
1
"2"
3
'4'

// 如果要显示3引号,至少转义1个引号
let str = """
Escaping the first quote \"""
Escaping two quotes \"\""
Escaping all three quotes \"\"\"
"""
Escaping the first quote """
Escaping two quotes """
Escaping all three quotes """

// 缩进以结尾的3引号为对齐线
let str = """
1
2
3
4
"""
//输出格式
1
2
3
4

// 以下2个字符串是等价的
let str1 = "These are the same."
let str2 = """
These are the same.
"""

String 与 NSString

  • String 与 NSString 之间可以随时随地桥接转换
  • 如果觉得String的API过于复杂难用,可以考虑将String转为NSString
    1
    2
    3
    4
    5
    6
    7
    8
    9
    var str1: String = "jack"
    var str2: NSString = "rose"

    var str3 = str1 as NSString
    var str4 = str2 as String

    // ja
    var str5 = str3.substring(with: NSRange(location: 0, length: 2))
    print(str5)
  • 比较字符串内容是否等价
    • String使用 == 运算符
    • NSString使用isEqual方法,也可以使用 == 运算符(本质还是调用了isEqual方法)

Swift、OC桥接转换表

1
2
3
4
5
6
7
8
String  NSString
String NSMutableString
Array NSArray
Array NSMutableArray
Dictionary NSDictionary
Dictionary NSMutableDictionary
Set NSSet
Set NSMutableSet

参考

  • 李明杰老师课件