Swift Optional Type
Bài đăng này đã không được cập nhật trong 9 năm
Kiểu Optional là gì ?
- Kiểu Optional : cho phép gán nil
- Không phải kiểu Optional : không cho phép gán nil
Phương pháp khai báo kiểu Optional
var a: Int? // Kiểu Optional
var b: Int // Không phải kiểu Optional
var c: String? // Kiểu Optional
var d: String // Không phải kiểu Optional
T?
là syntactic sugar của Optional<T>
var a: Int?
var b: Optional<Int> // tương đương với Int?
Kiểu Optional cho phép gán nil
var a: Int? // Kiểu Optional
a = nil // Không phát sinh compile error
var b: Int // Không phải kiểu optional
b = nil // Compile error : Could not find an overload for '__conversion' that accepts the supplied arguments
Giá trị khởi tạo của kiểu Optional là nil
Giá trị khởi tạo của kiểu Optional là nil.
var a: Int? // Kiểu Optional
println(a) // -> nil
Nếu không phải là kiểu Optional thì không có gì trong giá trị khởi tạo (không có cả nil)
var b: Int // Không phải kiểu Optional
println(b) // Compile error: Variable 'b' used before being initialized
Kiểu Optional không thể xử lý giống kiểu không phải Optional
var a: Int = 1
println(a + 2) // -> 3
var b: Int? = 1
println(b + 2) // Compile error: Value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?
Theo như trên, thì Int?
là kiểu khác với Int
nên không thể thao tác giống vây được. để có thể xử lý giống với Int
thì cần phải unwrap.(mô tả bên dưới).
Wrap và unwrap
【Đang được wrap】là gì?
Biến số có kiểu Optional (kiểu Optional<T>
) gọi là『đang được wrap』.
【Unwrap】?
Việc lấy ra biến kiểu T từ kiểu Optional(kiểu Optional<T>
)được gọi là 『Unwrap』.
Phương pháp unwrap biến kiểu Optional
Có những phương pháo dưới dùng để unwrap biến kiểu Optional
- Forced Unwrapping
- Optional Chaining
- Optional Binding
- Implicitly Unwrapped Optional Type
1. Forced Unwrapping
Sử dụng !
như dưới đây để có thể unwrap biến kiểu Optional.
class Dog {
func bark() -> String {
return "Wan!"
}
}
var d: Dog? = Dog() // Kiểu Optional
// Không thể call method bark nếu vẫn là trạng thái đã wrap
println(d.bark()) // Compile error: 'Dog?' does not have a member named 'bark'
// Có thể unwrap bằng cách thêm 「!」 vào sau biến d (Forced Unwrapping)
println(d!.bark()) // -> Wan!
// Nếu biến d là nil thì sẽ phát sinh runtime error khi unwrap bằng 「!」
d = nil
println(d!.bark()) // Runtime error: fatal error: Can't unwrap Optional.None
2. Optional Chaining
Sử dụng ?
chứ không phải !
như bên dưới đây để unwrap.
class Dog {
func bark() -> String {
return "Wan!"
}
}
var d: Dog? = Dog() // Kiểu Optional
// Nếu thêm 「?」 vào phía sau biến d thì sẽ unwrap (Optional Chaining)
println(d?.bark()) // -> Wan!
// Nếu biến d là nil thì unwrap sẽ trả lại nil
d = nil
println(d?.bark()) // -> nil
Khác với Forced Unwrapping, cho dù unwrap cho nil thì cũng không phát sinh runtime error, mà thay vào đó sẽ trả về nil.
Chú ý: về println
Kết quả output của println(d?.bark())
sẽ khác với xcode version mới nhất nên phải chú ý.
- Nếu là Xcode 6 Beta(version đã sử dụng để viết trong bài này)
println(d?.bark()) // -> Wan!
- Nếu là Xcode 6.1 GM seed 2
println(d?.bark()) // -> Optional(Wan!)
Khi output variable kiểu optional bằng println
thì chuỗi Optional()
sẽ được thêm vào.
3. Optional Binding
Biến được gán bằng kiểu Optional mà được khai báo trong biểu thức điều kiện IF
hay WHILE
thì trở thành kiểu không phải là Optional.
class Dog {
func bark() -> String {
return "Wan!"
}
}
var wrappedDog: Dog? = Dog() // Kiểu Optional
// Biến được khai báo trong câu IF sẽ trở thành không phải kiểu Optional(Optional Binding)
if var unwrappedDog1 = wrappedDog {
// Không cần phải thêm「!」
println(unwrappedDog1.bark()) // -> Wan!
}
// Khai báo「var」と「let」đều được
if let unwrappedDog2 = wrappedDog {
println(unwrappedDog2.bark()) // -> Wan!
}
// Có thể sử dung Optional Binding trong câu WHILE
while var unwrappedDog3 = wrappedDog {
println(unwrappedDog3.bark()) // -> Wan!
break
}
///////////////
// Bổ sung 1 //
///////////////
//
// Các biến「unwrappedDog1」「unwrappedDog2」「unwrapedDog3」 bên trên chỉ hữu hiệu trong block
//
println(unwrappedDog1.bark()) // Compile error: Use of unresolved identifier 'unwrappedDog1'
println(unwrappedDog2.bark()) // Compile error: Use of unresolved identifier 'unwrappedDog2'
println(unwrappedDog3.bark()) // Compile error: Use of unresolved identifier 'unwrappedDog3'
///////////////
// Bổ sung 2 //
///////////////
//
// Trong trường hợp wrappedDog là nil, kết quả của điều kiện câu IF là false nên ko thực hiện xử lý trong block
//
wrappedDog = nil
if var unwrappedDog4 = wrappedDog { // false
println("This is not printed out.") // -> không output gì
}
4. Kiểu Implicitly Unwrapped Optional
Nếu sử dụng kiểu Implicitly Unwrapped Optional chứ không phải kiểu Optional(Optional<T>
) thì có thể unwrap ngầm. Khi khai báo biến kiểu Implicitly Unwrapped Optional thì sử dụng !
chứ không phải ?
.
class Dog {
func bark() -> String {
return "Wan!"
}
}
// Khai báo bằng 「!」chứ ko phải bằng「?」
var d: Dog! = Dog() // Kiểu Implicitly Unwrapped Optional
// Không cần thực hiện unwrap(đã unwrap ngầm)
println(d.bark()) // -> Wan!
// Nếu biến d là nil, khi unwrap ngầm sẽ bị runtime error
d = nil
println(d.bark()) // Runtime error: fatal error: Can't unwrap Optional.None
T!
là syntactic sugar của ImplicitlyUnwrappedOptional<T>
var a: Int! // Kiểu Implicitly Unwrapped Optional
var b: ImplicitlyUnwrappedOptional<Int> // Tương đương với Int!
Điểm khác nhau giữa kiểu Optional & kiểu Implicitly Unwrapped Optional
Type | Khai báo | Entity of type | Thao tác khi unwrap |
---|---|---|---|
Optional | var a: T? | Optional<T> |
Cần thao tác rõ ràng |
Implicitly Unwrapped Optional | var a: T! | ImplicitlyUnwrappedOptional<T> |
Không cần (được unwrap ngầm) |
Cách xử lý trong trường hợp đã unwrap cho nil
Trường hợp là kiểu Optional (Optional<T>
)
Phương pháp unwrap | Kết quả |
---|---|
Trường hợp là Forced Unwrapping (phương pháp sử dụng ! ) |
Phát sinh runtime error |
Trường hợp là Optional Chaining (phương pháp sử dụng ? ) |
Trả về nil |
class Dog {
func bark() -> String {
return "Wan!"
}
}
var d: Dog? = nil // Kiểu Optional
// Trường hợp Forced Unwrapping (sử dụng !)
println(d!.bark()) // Runtime error: fatal error: Can't unwrap Optional.None
// Trường hợp Optional Chaining (Sử dụng ?)
println(d?.bark()) // -> nil
Trường hợp là kiểu Implicitly Unwrapped Optional (ImplicitlyUnwrappedOptional<T>
)
Phương pháp unwrap | Kết quả |
---|---|
Unwrap ngầm | Phát sinh runtime error |
class Dog {
func bark() -> String {
return "Wan!"
}
}
var d: Dog! = nil // Kiểu Implicitly Unwrapped Optional
println(d.bark()) // Runtime error: fatal error: Can't unwrap Optional.None
Develop enviroment
Xcode 6 Beta
Mac OS X 10.9.3
Run enviroment
iOS Simulator (iPhone5s / iOS 8.0)
Source: http://qiita.com/cotrpepe/items/e30c7442733b93adf46a
All rights reserved