Swift - jakich typów użyć? NSString lub String

109

Wraz z wprowadzeniem języka Swift starałem się ogarnąć nowy język

Jestem programistą iOS i używam typów, takich jak NSString, NSInteger, NSDictionaryw aplikacji. Zauważyłem, że w ebooku „The Swift Programming Language” firmy Apple używają typów SwiftString, Int, Dictionary

Zauważyłem, że typy Swift nie mają (lub są inaczej nazywane) niektórych funkcji, które pełnią typy Foundation. Na przykład NSStringma lengthwłaściwość. Ale nie udało mi się znaleźć podobnego dla Swifta String.

Zastanawiam się, czy w przypadku aplikacji na iOS powinienem nadal używać typów Foundation?

Alec
źródło
3
Preferuj String. Jednak Stringfunkcjonalność w wersji alfa jest nadal nieco ograniczona, więc na razie NSStringbędzie bardziej używana. Mamy nadzieję, że naprawią API do czasu GA.
Sulthan
1
Możesz także zadzwonić countElements(str), aby odpowiedzieć na konkretną część pytania.
Nate Cook
Lepiej, możesz wywołać "foo".length" directly in Swift. An implicit cast to NSString`, który jest dodawany przez kompilator!
Gabriele Petronella
1
@GabrielePetronella .length może nie działać poprawnie w przypadku znaków specjalnych. Na przykład emoji lub chińskie znaki, które zajmują 2 lub 3 znaki Unicode. countElements jest właściwą metodą do użycia.
Fogmeister

Odpowiedzi:

98

W miarę możliwości należy używać typów natywnych Swift. Język jest zoptymalizowany pod kątem ich używania, a większość funkcji jest połączona pomostem między typami natywnymi i Foundationtypami.

Choć Stringi NSStringto w większości wymienne, to znaczy można przekazać Stringzmienne do metod, które mają NSStringparametry i odwrotnie, niektóre metody wydają się nie być automatycznie mostkiem jak od tej chwili. Zobacz tę odpowiedź, aby zapoznać się z dyskusją o tym, jak uzyskać długość ciągu, a tę odpowiedź,containsString() aby zapoznać się z dyskusją na temat używania do sprawdzania podciągów. (Zastrzeżenie: jestem autorem obu odpowiedzi)

Nie zbadałem w pełni innych typów danych, ale zakładam, że niektóre wersje tego, co zostało powiedziane powyżej, będą również obowiązywać dla Array/ NSArray, Dictionary/ NSDictionaryoraz różnych typów liczbowych w Swift iNSNumber

Ilekroć musisz użyć jednego z typów Foundation, możesz użyć ich do jawnego wpisania zmiennych / stałych, jak w, var str: NSString = "An NSString"lub użyć bridgeToObjectiveC()na istniejącej zmiennej / stałej typu Swift, jak str.bridgeToObjectiveC().lengthna przykład. Możesz także przesłać a Stringdo NSString, używając str as NSString.

Jednak konieczność, aby te techniki wyraźnie używały typów Foundation lub przynajmniej niektórych z nich, może być w przyszłości przestarzała, ponieważ z tego, co jest określone w odwołaniu do języka , na przykład String/ NSStringbridge powinien być całkowicie płynny.

Dokładną dyskusję na ten temat można znaleźć w dokumencie Using Swift with Cocoa and Objective-C: Working with Cocoa Data Types

Cezar
źródło
4
+1 dla odniesienia do bridgeToObjectiveC()i wyjaśnienia związku między NSString a ciągiem Swift's.
Chris
2
hej cezar, myślę, że bridgeToObjectiveC jest przestarzały, jeśli chcesz zaktualizować swoją odpowiedź.
Dan Beaulieu
W podręczniku Swift 3 zauważyłem, że typy Foundation są przekazywane przez odwołanie, podczas gdy typy natywne są przekazywane przez wartość (lub coś takiego, czego nie w pełni rozumiem w tym momencie). Byłoby wspaniale, gdybyś mógł zaktualizować swoją odpowiedź, omawiając konsekwencje tego.
Nigel B. Peck
27

NSString: tworzy obiekty, które znajdują się w stercie i są zawsze przekazywane przez odwołanie.

Łańcuch: Jest to typ wartości za każdym razem, gdy go przekazujemy, jest przekazywany przez wartość. podobnie jak Struct i Enum, String sam w sobie jest Struct w języku Swift.

public struct String {
 // string implementation 
}

Ale kopia nie jest tworzona, gdy zdasz. Tworzy kopię przy pierwszej mutacji.

Ciąg jest automatycznie mostkowany do Objective-C jako NSString. Jeśli biblioteka Swift Standard nie ma, musisz zaimportować framework Foundation, aby uzyskać dostęp do metod zdefiniowanych przez NSString.

Swift String jest bardzo potężny i ma mnóstwo wbudowanych funkcji.

Inicjalizacja na łańcuchu:

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"

utwórz ciąg z powtarzających się wartości:

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

W Swift 4 -> Ciągi są zbiorem znaków:

Teraz String jest w stanie wykonać wszystkie operacje, które każdy może wykonać na typie Collection.

Więcej informacji można znaleźć w dokumentach Apple.

Sandy Rawat
źródło
2
Ta odpowiedź powinna uzyskać więcej głosów pozytywnych. To jest podstawowa różnica między String i NSString. Wszędzie indziej są prawie wymienne
maksymalnie
Świetna odpowiedź. Zwłaszcza wartość vs typ ref.
spnkr
11

Najlepszym rozwiązaniem jest użycie natywnych typów i klas Swift, jak niektórzy zauważyli, że NSString ma bezpłatne tłumaczenie na String, jednak nie są one takie same w 100%, weź na przykład następujące

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

nsstring.length
count(string)

musisz użyć metody count (), aby policzyć znaki w łańcuchu, pamiętaj również, że nsstring.length zwraca 2, ponieważ zlicza swoją długość na podstawie UTF16.

Podobnie, TAK To samo, NIE

Emanuel
źródło
7

Stringi NSStringsą wymienne, więc nie ma znaczenia, którego z nich użyjesz. Zawsze możesz przesyłać między nimi, używając

let s = "hello" as NSString

lub nawet

let s: NSString  = "hello"

NSIntegerjest po prostu aliasem dla a intlub a long(w zależności od architektury), więc po prostu użyję Int.

NSDictionaryto inna sprawa, ponieważ Dictionaryjest to zupełnie odrębna implementacja.

Ogólnie rzecz biorąc, trzymałbym się szybkich typów, gdy tylko jest to możliwe, i zawsze możesz dokonać konwersji między nimi w razie potrzeby, używając bridgeToObjectiveC()metody zapewnianej przez klasy Swift.

Gabriele Petronella
źródło
W Intksiążce podano, że typ danych języka Swift jest taki sam, jak rozmiar słowa architektury. NSIntegerjest również taki sam jak rozmiar słowa architektury.
MaddTheSane
6

Ponieważ obiektywne typy C są nadal dynamicznie wysyłane, prawdopodobnie będą wolniejsze. Powiedziałbym, że najlepiej jest ci służyć przy użyciu typów natywnych Swift, chyba że musisz wchodzić w interakcje z API Objective-c

Jiaaro
źródło
Tak, to jest dokładnie odpowiedź. A unikanie dynamicznie wysyłanych metod i dostępu do zmiennych obiektów jest wszystkim, co powoduje poprawę szybkości, o której rozmawiali na WWDC. W przeszłości wszyscy martwili się o wydajność, używając ciągów znaków C ++ i kontenerów do wysyłania statycznego.
Lothar
5

Używaj rodzimych typów Swift, kiedy tylko możesz. Jednak w przypadku String masz „bezproblemowy” dostęp do wszystkich NSStringmetod, takich jak ta:

var greeting = "Hello!"
var len = (greeting as NSString).length
Nate Cook
źródło
4

Aktualizacja Swift 4

String otrzymuje poprawki w swift 4. Teraz możesz bezpośrednio wywołać liczenie na nim i traktuje klastry grafemów jako 1 element, jak emoji. NSString nie jest aktualizowany i liczy go w inny sposób.

var nsstring: NSString = "👩‍👩‍👧‍👦"
var string: String = "👩‍👩‍👧‍👦"

print(nsstring.length) // 11
print(string.count)    // 1
Fangming
źródło
1
NSStringPrawdopodobnie nie zostaną zaktualizowane, aby poradzić sobie z klastrami grafemów: spowodowałoby to uszkodzenie zbyt wielu aplikacji, które opierają się na starym zachowaniu. Również NSString.lengthzlicza znaki UTF16.
MaddTheSane,
0

Ciąg jest strukturą

// w Swift Module

public struct String

{

}

NSString to klasa

// w module podstawowym

otwarta klasa NSString: NSObject

{

}

kaszish makkar
źródło