Skip to content

Commit eaefb5e

Browse files
committed
String's NSString API: Replace factory methods with failable initializers.
Addresses rdar://problem/18225788. Swift SVN r21710
1 parent fa36bab commit eaefb5e

File tree

4 files changed

+99
-68
lines changed

4 files changed

+99
-68
lines changed

apinotes/Foundation.apinotes

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8377,7 +8377,7 @@ Classes:
83778377
Nullability:
83788378
- S
83798379
- S
8380-
NullabilityOfRet: N
8380+
NullabilityOfRet: O
83818381
- Selector: 'initWithData:encoding:'
83828382
MethodKind: Instance
83838383
Nullability:
@@ -8406,7 +8406,7 @@ Classes:
84068406
MethodKind: Instance
84078407
Nullability:
84088408
- S
8409-
NullabilityOfRet: N
8409+
NullabilityOfRet: O
84108410
- Selector: 'isEqualToString:'
84118411
MethodKind: Instance
84128412
Nullability:

stdlib/objc/Foundation/NSStringAPI.swift

Lines changed: 78 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -192,75 +192,96 @@ extension String {
192192
// encoding:(NSStringEncoding)enc
193193
// error:(NSError **)error
194194

195-
/// Returns a string created by reading data from the file at a
195+
/// Produces a string created by reading data from the file at a
196196
/// given path interpreted using a given encoding.
197-
public static func stringWithContentsOfFile(
198-
path: String,
197+
public init?(
198+
contentsOfFile path: String,
199199
encoding enc: NSStringEncoding,
200200
error: NSErrorPointer = nil
201-
) -> String? {
202-
return NSString(contentsOfFile: path, encoding: enc, error: error)
201+
) {
202+
if let ns = NSString(contentsOfFile: path, encoding: enc, error: error) {
203+
self = ns as String
204+
} else {
205+
return nil
206+
}
203207
}
204208

205209
// + (instancetype)
206210
// stringWithContentsOfFile:(NSString *)path
207211
// usedEncoding:(NSStringEncoding *)
208212
// enc error:(NSError **)error
209213

210-
/// Returns a string created by reading data from the file at
214+
/// Produces a string created by reading data from the file at
211215
/// a given path and returns by reference the encoding used to
212216
/// interpret the file.
213-
public static func stringWithContentsOfFile(
214-
path: String,
217+
public init?(
218+
contentsOfFile path: String,
215219
usedEncoding: UnsafeMutablePointer<NSStringEncoding> = nil,
216220
error: NSErrorPointer = nil
217-
) -> String? {
218-
return NSString(contentsOfFile: path, usedEncoding: usedEncoding,
219-
error: error)
221+
) {
222+
if let ns = NSString(contentsOfFile: path, usedEncoding: usedEncoding,
223+
error: error) {
224+
self = ns as String
225+
} else {
226+
return nil
227+
}
220228
}
221229

222230
// + (instancetype)
223231
// stringWithContentsOfURL:(NSURL *)url
224232
// encoding:(NSStringEncoding)enc
225233
// error:(NSError **)error
226234

227-
/// Returns a string created by reading data from a given URL
235+
/// Produces a string created by reading data from a given URL
228236
/// interpreted using a given encoding. Errors are written into the
229237
/// inout `error` argument.
230-
public static func stringWithContentsOfURL(
231-
url: NSURL, encoding enc: NSStringEncoding, error: NSErrorPointer = nil
232-
) -> String? {
233-
return NSString(contentsOfURL: url, encoding: enc, error: error)
238+
public init?(
239+
contentsOfURL url: NSURL,
240+
encoding enc: NSStringEncoding,
241+
error: NSErrorPointer = nil
242+
) {
243+
if let ns = NSString(contentsOfURL: url, encoding: enc, error: error) {
244+
self = ns as String
245+
} else {
246+
return nil
247+
}
234248
}
235249

236250
// + (instancetype)
237251
// stringWithContentsOfURL:(NSURL *)url
238252
// usedEncoding:(NSStringEncoding *)enc
239253
// error:(NSError **)error
240254

241-
/// Returns a string created by reading data from a given URL
255+
/// Produces a string created by reading data from a given URL
242256
/// and returns by reference the encoding used to interpret the
243257
/// data. Errors are written into the inout `error` argument.
244-
public static func stringWithContentsOfURL(
245-
url: NSURL,
258+
public init?(
259+
contentsOfURL url: NSURL,
246260
usedEncoding enc: UnsafeMutablePointer<NSStringEncoding> = nil,
247261
error: NSErrorPointer = nil
248-
) -> String? {
249-
return NSString(contentsOfURL: url, usedEncoding: enc,
250-
error: error)
262+
) {
263+
if let ns = NSString(contentsOfURL: url, usedEncoding: enc, error: error) {
264+
self = ns as String
265+
} else {
266+
return nil
267+
}
251268
}
252269

253270
// + (instancetype)
254271
// stringWithCString:(const char *)cString
255272
// encoding:(NSStringEncoding)enc
256273

257-
/// Returns a string containing the bytes in a given C array,
274+
/// Produces a string containing the bytes in a given C array,
258275
/// interpreted according to a given encoding.
259-
public static func stringWithCString(
260-
cString: UnsafePointer<CChar>,
276+
public init?(
277+
CString: UnsafePointer<CChar>,
261278
encoding enc: NSStringEncoding
262-
) -> String? {
263-
return NSString(CString: cString, encoding: enc)
279+
) {
280+
if let ns = NSString(CString: CString, encoding: enc) {
281+
self = ns as String
282+
} else {
283+
return nil
284+
}
264285
}
265286

266287

@@ -270,12 +291,14 @@ extension String {
270291

271292
// + (instancetype)stringWithUTF8String:(const char *)bytes
272293

273-
/// Returns a string created by copying the data from a given
294+
/// Produces a string created by copying the data from a given
274295
/// C array of UTF8-encoded bytes.
275-
public static func stringWithUTF8String(
276-
bytes: UnsafePointer<CChar>
277-
) -> String? {
278-
return NSString(UTF8String: bytes)
296+
public init?(UTF8String bytes: UnsafePointer<CChar>) {
297+
if let ns = NSString(UTF8String: bytes) {
298+
self = ns as String
299+
} else {
300+
return nil
301+
}
279302
}
280303

281304
//===--- Instance Methods/Properties-------------------------------------===//
@@ -729,17 +752,21 @@ extension String {
729752
// length:(NSUInteger)length
730753
// encoding:(NSStringEncoding)encoding
731754

732-
/// Returns an initialized `NSString` object equivalent to the given
755+
/// Produces an initialized `NSString` object equivalent to the given
733756
/// `bytes` interpreted in the given `encoding`.
734-
public static func stringWithBytes<
757+
public init? <
735758
S: SequenceType where S.Generator.Element == UInt8
736759
>(
737760
bytes: S, encoding: NSStringEncoding
738-
) -> String? {
761+
) {
739762
let byteArray = Array(bytes)
740-
return NSString(
741-
bytes: byteArray, length: byteArray.count, encoding: encoding
742-
) as NSString? // HACK: FIXME: coerce to optional NSString to handle nil
763+
if let ns = NSString(
764+
bytes: byteArray, length: byteArray.count, encoding: encoding
765+
) {
766+
self = ns as String
767+
} else {
768+
return nil
769+
}
743770
}
744771

745772
// - (instancetype)
@@ -748,18 +775,22 @@ extension String {
748775
// encoding:(NSStringEncoding)encoding
749776
// freeWhenDone:(BOOL)flag
750777

751-
/// Returns an initialized `String` object that contains a
778+
/// Produces an initialized `String` object that contains a
752779
/// given number of bytes from a given buffer of bytes interpreted
753780
/// in a given encoding, and optionally frees the buffer. WARNING:
754-
/// this method is not memory-safe!
755-
public static func stringWithBytesNoCopy(
756-
bytes: UnsafeMutablePointer<Void>, length: Int,
781+
/// this initializer is not memory-safe!
782+
public init?(
783+
bytesNoCopy bytes: UnsafeMutablePointer<Void>, length: Int,
757784
encoding: NSStringEncoding, freeWhenDone flag: Bool
758-
) -> String? {
759-
return NSString(
760-
bytesNoCopy: bytes, length: length,
761-
encoding: encoding, freeWhenDone: flag
762-
) as NSString? // Important: coerce to optional NSString to handle nil
785+
) {
786+
if let ns = NSString(
787+
bytesNoCopy: bytes, length: length,
788+
encoding: encoding, freeWhenDone: flag
789+
) {
790+
self = ns as String
791+
} else {
792+
return nil
793+
}
763794
}
764795

765796

test/stdlib/NSStringAPI.swift

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ NSStringAPIs.test("stringWithContentsOfFile(_:encoding:error:)") {
8989
let (existingPath, nonExistentPath) = createNSStringTemporaryFile()
9090
if true {
9191
var err: NSError?
92-
let content = String.stringWithContentsOfFile(existingPath,
92+
let content = String(contentsOfFile: existingPath,
9393
encoding: NSASCIIStringEncoding, error: &err)
9494

9595
expectEmpty(err)
@@ -99,7 +99,7 @@ NSStringAPIs.test("stringWithContentsOfFile(_:encoding:error:)") {
9999
}
100100
if true {
101101
var err: NSError?
102-
let content = String.stringWithContentsOfFile(nonExistentPath,
102+
let content = String(contentsOfFile: nonExistentPath,
103103
encoding: NSASCIIStringEncoding, error: &err)
104104

105105
expectNotEmpty(err)
@@ -112,7 +112,7 @@ NSStringAPIs.test("stringWithContentsOfFile(_:usedEncoding:error:)") {
112112
if true {
113113
var usedEncoding: NSStringEncoding = 0
114114
var err: NSError?
115-
var content = String.stringWithContentsOfFile(existingPath,
115+
var content = String(contentsOfFile: existingPath,
116116
usedEncoding: &usedEncoding, error: &err)
117117

118118
expectNotEqual(0, usedEncoding)
@@ -124,7 +124,7 @@ NSStringAPIs.test("stringWithContentsOfFile(_:usedEncoding:error:)") {
124124
if true {
125125
var usedEncoding: NSStringEncoding = 0
126126
var err: NSError?
127-
var content = String.stringWithContentsOfFile(nonExistentPath, error: &err)
127+
var content = String(contentsOfFile: nonExistentPath, error: &err)
128128

129129
expectEqual(0, usedEncoding)
130130
expectNotEmpty(err)
@@ -139,7 +139,7 @@ NSStringAPIs.test("stringWithContentsOfURL(_:encoding:error:)") {
139139
let nonExistentURL = NSURL(string: "file://" + nonExistentPath)!
140140
if true {
141141
var err: NSError?
142-
var content = String.stringWithContentsOfURL(existingURL,
142+
var content = String(contentsOfURL: existingURL,
143143
encoding: NSASCIIStringEncoding, error: &err)
144144

145145
expectEmpty(err)
@@ -149,7 +149,7 @@ NSStringAPIs.test("stringWithContentsOfURL(_:encoding:error:)") {
149149
}
150150
if true {
151151
var err: NSError?
152-
var content = String.stringWithContentsOfURL(nonExistentURL,
152+
var content = String(contentsOfURL: nonExistentURL,
153153
encoding: NSASCIIStringEncoding, error: &err)
154154

155155
expectNotEmpty(err)
@@ -164,7 +164,7 @@ NSStringAPIs.test("stringWithContentsOfURL(_:usedEncoding:error:)") {
164164
if true {
165165
var usedEncoding: NSStringEncoding = 0
166166
var err: NSError?
167-
var content = String.stringWithContentsOfURL(existingURL,
167+
var content = String(contentsOfURL: existingURL,
168168
usedEncoding: &usedEncoding, error: &err)
169169

170170
expectNotEqual(0, usedEncoding)
@@ -176,7 +176,7 @@ NSStringAPIs.test("stringWithContentsOfURL(_:usedEncoding:error:)") {
176176
if true {
177177
var usedEncoding: NSStringEncoding = 0
178178
var err: NSError?
179-
var content = String.stringWithContentsOfURL(nonExistentURL,
179+
var content = String(contentsOfURL: nonExistentURL,
180180
usedEncoding: &usedEncoding, error: &err)
181181

182182
expectEqual(0, usedEncoding)
@@ -187,11 +187,11 @@ NSStringAPIs.test("stringWithContentsOfURL(_:usedEncoding:error:)") {
187187

188188
NSStringAPIs.test("stringWithCString(_:encoding:)") {
189189
expectOptionalEqual("foo, a basmati bar!",
190-
String.stringWithCString(
190+
String(CString:
191191
"foo, a basmati bar!", encoding: String.defaultCStringEncoding()))
192192
}
193193

194-
NSStringAPIs.test("stringWithUTF8String(_:)") {
194+
NSStringAPIs.test("init(UTF8String:)") {
195195
var s = "foo あいう"
196196
var up = UnsafeMutablePointer<UInt8>.alloc(100)
197197
var i = 0
@@ -200,7 +200,7 @@ NSStringAPIs.test("stringWithUTF8String(_:)") {
200200
i++
201201
}
202202
up[i] = 0
203-
expectOptionalEqual(s, String.stringWithUTF8String(UnsafePointer(up)))
203+
expectOptionalEqual(s, String(UTF8String: UnsafePointer(up)))
204204
up.dealloc(100)
205205
}
206206

@@ -708,10 +708,10 @@ NSStringAPIs.test("hash") {
708708
expectEqual(nsstr.hash, s.hash)
709709
}
710710

711-
NSStringAPIs.test("stringWithBytes(_:encoding:)") {
711+
NSStringAPIs.test("init(bytes:encoding:)") {
712712
var s: String = "abc あかさた"
713713
expectOptionalEqual(
714-
s, String.stringWithBytes(s.utf8, encoding: NSUTF8StringEncoding))
714+
s, String(bytes: s.utf8, encoding: NSUTF8StringEncoding))
715715

716716
/*
717717
FIXME: Test disabled because the NSString documentation is unclear about
@@ -724,10 +724,10 @@ NSStringAPIs.test("stringWithBytes(_:encoding:)") {
724724
// FIXME: add a test where this function actually returns nil.
725725
}
726726

727-
NSStringAPIs.test("stringWithBytesNoCopy(_:length:encoding:freeWhenDone:)") {
727+
NSStringAPIs.test("init(bytesNoCopy:length:encoding:freeWhenDone:)") {
728728
var s: String = "abc あかさた"
729729
var bytes: [UInt8] = Array(s.utf8)
730-
expectOptionalEqual(s, String.stringWithBytesNoCopy(&bytes,
730+
expectOptionalEqual(s, String(bytesNoCopy: &bytes,
731731
length: bytes.count, encoding: NSUTF8StringEncoding,
732732
freeWhenDone: false))
733733

@@ -1532,7 +1532,7 @@ NSStringAPIs.test("writeToFile(_:atomically:encoding:error:)") {
15321532
expectTrue(result)
15331533

15341534
expectOptionalEqual(
1535-
s, String.stringWithContentsOfFile(
1535+
s, String(contentsOfFile:
15361536
nonExistentPath, encoding: NSASCIIStringEncoding))
15371537
}
15381538
}
@@ -1550,7 +1550,7 @@ NSStringAPIs.test("writeToURL(_:atomically:encoding:error:)") {
15501550
expectTrue(result)
15511551

15521552
expectOptionalEqual(
1553-
s, String.stringWithContentsOfFile(
1553+
s, String(contentsOfFile:
15541554
nonExistentPath, encoding: NSASCIIStringEncoding))
15551555
}
15561556
}

test/stdlib/NewString.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func nonASCII() {
7676
// Cocoa stores non-ASCII in a UTF-16 buffer
7777
// Code units in each character: 2 1 1 1 2 2 2
7878
// Offset of each character: 0 2 3 4 5 7 9 11
79-
var nsUTF16 = NSString(UTF8String: "🏂☃❅❆❄︎⛄️❄️")
79+
var nsUTF16 = NSString(UTF8String: "🏂☃❅❆❄︎⛄️❄️")!
8080
// CHECK-NEXT: has UTF-16: true
8181
println("has UTF-16: \(CFStringGetCharactersPtr(unsafeBitCast(nsUTF16, CFString.self)) != nil)")
8282

@@ -122,7 +122,7 @@ func ascii() {
122122
// Cocoa stores ASCII in a buffer of bytes. This is an important case
123123
// because it doesn't provide a contiguous array of UTF-16, so we'll be
124124
// treating it as an opaque NSString.
125-
var nsASCII = NSString(UTF8String: "foobar")
125+
var nsASCII = NSString(UTF8String: "foobar")!
126126
// CHECK-NEXT: has UTF-16: false
127127
println("has UTF-16: \(CFStringGetCharactersPtr(unsafeBitCast(nsASCII, CFString.self)) != nil)")
128128

0 commit comments

Comments
 (0)