Swift - 应该使用哪种类型?NSString还是String?

116

随着Swift的推出,我一直在尝试理解这种新语言。

作为iOS开发人员,我会在应用程序中使用NSString, NSInteger, NSDictionary等类型。我注意到,在苹果公司的"Swift编程语言"电子书中,他们使用了Swift类型String, Int, Dictionary

我注意到,Swift类型没有(或者名称不同)一些Foundation类型拥有的函数。例如,NSString具有length属性。但是我并未能找到类似于Swift String的属性。

我想知道,在iOS应用程序中,我是否仍应该使用Foundation类型?


3
建议优先使用String。然而,在alpha版本中,String功能还有些受限,因此现在更多地使用NSString。我们希望在正式发布之前能够修复API问题。 - Sulthan
1
你也可以调用 countElements(str) 来回答你问题中的特定部分。 - Nate Cook
更好的是,在Swift中可以直接调用"foo".length。编译器会为您添加一个隐式转换到NSString - Gabriele Petronella
1
@GabrielePetronella .length 可能无法正确处理特殊字符,例如占用2或3个Unicode字符的表情符号或中文字符。countElements是正确的方法。 - Fogmeister
9个回答

105

尽可能使用Swift的本地类型。该语言已经对其进行了优化,并且大多数功能已在本地类型和Foundation类型之间进行了桥接。

虽然StringNSString可以互换使用,即您可以将String变量传递到需要NSString参数的方法中,反之亦然,但某些方法似乎目前还不能自动桥接。有关如何获取字符串长度的讨论,请参见此答案,有关使用containsString()检查子字符串的讨论,请参见此答案。(免责声明:我是这两个答案的作者)

我尚未完全探索其他数据类型,但我认为所述内容的某个版本也适用于Array/NSArrayDictionary/NSDictionary和Swift和NSNumber中的各种数字类型。

每当需要使用其中一个Foundation类型时,您可以显式地将它们用于类型变量/常量,例如var str: NSString = "An NSString"或在现有的Swift类型变量/常量上使用bridgeToObjectiveC(),例如str.bridgeToObjectiveC().length。您还可以通过使用str as NSStringString转换为NSString

但是,由于语言参考中所述的内容,这些技术明确使用Foundation类型或至少某些Foundation类型的必要性在未来可能已经过时,例如,String/NSString桥应该是完全无缝的。

要全面讨论此主题,请参见使用Swift与Cocoa和Objective-C:使用Cocoa数据类型


6
+1 是指对 bridgeToObjectiveC() 的引用,并解释 NSString 和 Swift 的 String 之间的联系。 - Chris
2
嗨,Cezar,如果你想更新你的答案,我认为bridgeToObjectiveC已经被弃用了。 - Dan Beaulieu
我注意到在Swift 3手册中,Foundation类型是通过引用传递的,而本地类型是按值传递的(或者类似于这样,我目前还没有完全理解)。如果您能更新您的答案并讨论其影响,那将是非常好的。 - user2493235

36

NSString:创建在堆中驻留并始终通过引用传递的对象。

String:它是一个值类型,无论何时我们传递它,都是按值传递的。 就像结构体和枚举一样,在Swift中,String本身就是一个结构体。

public struct String {
 // string implementation 
}

然而在传递时并不会创建副本,只有在首次进行变异时才会创建副本。

String 会自动桥接到 Objective-C 中作为 NSString。如果 Swift 标准库中没有相关方法,需要导入 Foundation 框架才能访问 NSString 定义的方法。

Swift String 非常强大,拥有大量内置函数。

字符串的初始化:

var emptyString = ""             // Empty (Mutable)
let anotherString = String()     // empty String immutable    
let a = String(false)           // from boolean: "false"
let d = String(5.999)           //  "    Double "5.99"
let e = String(555)             //  "     Int "555"
// New in Swift 4.2 
let hexString = String(278, radix: 18, uppercase: true) // "F8"

使用重复的值创建字符串:

 let repeatingString = String(repeating:"123", count:2) // "123123"

在 Swift 4 中 -> 字符串是字符的集合:

现在,字符串能够执行任何集合类型可以执行的操作。

有关更多信息,请参阅苹果文档。


2
这个回答应该得到更多的赞。这是String和NSString之间的根本区别。在其他地方,它们几乎可以互换。 - Max
1
很棒的答案。特别是关于值类型和引用类型的注意事项。 - spnkr

12

你最好使用Swift的本地类型和类,正如其他人所指出的,NSString具有与String无缝转换的能力,但它们并不完全相同,例如:

var nsstring: NSString = "\U0001F496"
var string: String = "\U0001F496"

nsstring.length
count(string)

你需要使用方法count()来计算字符串中的字符数量,同时注意NSString.length返回2,因为它基于UTF16计算长度。

相似,是的 相同,不是


7

StringNSString是可以互换的,所以你使用哪一个并不重要。你可以随时使用转换函数在两者之间进行转换。

let s = "hello" as NSString

甚至更多。
let s: NSString  = "hello"

NSInteger只是intlong(取决于架构)的别名,因此我建议使用Int

NSDictionary则不同,因为Dictionary是完全独立的实现。

一般来说,我会尽可能使用Swift类型,并且您可以在需要时使用由Swift类提供的bridgeToObjectiveC()方法在两者之间进行转换。


在书中,Swift的“Int”数据类型被说明为与体系结构的字长相同。 “NSInteger”也与体系结构的字长相同。 - MaddTheSane

7

Swift 4更新

Swift 4中对String进行了修订。现在你可以直接调用它的count属性,它将把基元素群集(如表情符号)作为1个整体来计算。NSString没有更新,会以另一种方式计算。

var nsstring: NSString = "‍‍‍"
var string: String = "‍‍‍"

print(nsstring.length) // 11
print(string.count)    // 1

1
NSString 可能不会更新以处理字形簇:这将破坏太多依赖旧行为的应用程序。另外,NSString.length 计算 UTF16 字符的数量。 - MaddTheSane

6

由于Objective-C类型仍然是动态分派的,因此它们可能会更慢。我建议您最好使用Swift本机类型,除非您需要与Objective-C API交互。


是的,那正是答案。避免动态分派方法和对象变量访问是WWDC所谈到的所有速度提升的原因。过去,每个人都担心性能问题,使用C++字符串和容器来获得静态分派。 - Lothar

5

尽可能使用Swift本地类型。但是,在字符串的情况下,您可以像这样“无缝”访问所有 NSString 方法:

var greeting = "Hello!"
var len = (greeting as NSString).length

1
Swift字符串非常优雅且易于使用,除非您需要解析它们。在Swift字符串中进行索引的整个概念就是疯狂的。每当我需要解析典型的Unicode字符串时,我将其转换为NSString。但是,在Swift中,这有点棘手,因为常见的“字符”整数表达式(如' '或'A'或'0')不起作用。您必须使用32、65、48。不幸的是,我并不是在开玩笑!因此,我将大部分字符串解析代码放到了Objective-C编写的NSString扩展中。
是的,我知道为什么Swift的设计者使String索引如此疯狂:他们想能够将许多字节的字符(如表情符号)表示为单个“字符”。我的选择是将这种罕见用例表达为多个UTF16字符,但是算了。

0

字符串是一个结构体

// 在 Swift 模块中

public struct String

{

}

NSString是一个类

// 在Foundation模块中

开放类NSString:NSObject

{

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接