2014-09-16 16 views
5

Tôi có đối tượng tùy chỉnh được gọi là Trường. Tôi về cơ bản sử dụng nó để xác định một trường đơn trong một biểu mẫu.Swift nếu để đánh giá thành công trên Tùy chọn (nil)

class Field { 

    var name: String 
    var value: Any? 

    // initializers here... 
} 

Khi người dùng gửi các hình thức, tôi xác nhận mỗi Field đối tượng để đảm bảo chúng chứa các giá trị hợp lệ. Một số lĩnh vực không phải vì vậy tôi đôi khi cố tình thiết lập nil đến value bất động sản như thế này:

field.value = nil 

Điều này dường như đặt ra một vấn đề khi tôi sử dụng một if-hãy để xác định xem một lĩnh vực là con số không hay không.

if let value = field.value { 
    // The field has a value, ignore it... 
} else { 
    // Add field.name to the missing fields array. Later, show the 
    // missing fields in a dialog. 
} 

tôi đặt breakpoint ở trên if-else và khi field.value đã được cố tình thiết lập để con số không, nó đi qua các khối if-let, không phải là ai khác. Tuy nhiên, đối với các trường có số field.value tôi không được khởi tạo và chưa được gán, chương trình sẽ chuyển đến khối khác.

tôi đã cố gắng in ra field.valuevalue bên trong khối if-phép:

if let value = field.value { 
    NSLog("field.value: \(field.value), value: \(value)") 
} 

Và đây là những gì tôi nhận được:

field.value: Tùy chọn (không), giá trị: nil

Vì vậy, tôi nghĩ rằng có thể với tùy chọn, đó là một điều không được khởi tạo và một điều khác để có valu e of nil. Nhưng thậm chí thêm một cái khác nếu bên trong if-let sẽ không làm cho trình biên dịch hài lòng:

if let value = field.value { 
    if value == nil { // Cannot invoke '==' with an argument list of type '(Any, NilLiteralConvertible)' 
    } 
} 

Làm cách nào để giải quyết vấn đề này? Tôi chỉ muốn kiểm tra xem field.value có phải là nil hay không.

+1

Không thể sao chép. Bạn sử dụng phiên bản Xcode nào? –

+0

Xcode 6 GM. Cố gắng khởi động lại nó, vẫn không có may mắn. :( –

+0

Bạn có thể đăng một ví dụ hoàn chỉnh khép kín thể hiện được vấn đề không? –

Trả lời

3

Tôi tin rằng điều này là do Any? cho phép bất kỳ giá trị nào và Optional.None đang được hiểu là một giá trị khác, vì Optional là một sự kiện!

AnyObject? không thể thực hiện việc này vì nó chỉ có thể chứa Optional.Some([any class object]), không cho phép đối với trường hợp Optional.Some(Optional) với giá trị Optional.None.

Điều này gây nhầm lẫn sâu sắc khi nói đến. Vấn đề là: thử AnyObject? thay vì Any? và xem điều đó có hiệu quả hay không.


Thêm vào điểm, một trong những bình luận của Matt đề cập rằng lý do ông muốn sử dụng Any là một lựa chọn có thể được, hoặc một lĩnh vực để nhập văn bản hoặc một lĩnh vực có ý định chọn một đối tượng Core Data.

Điều Swifty cần làm trong trường hợp này là sử dụng enum with associated values, về cơ bản giống như tagged/discriminated union.Dưới đây là cách khai báo, chuyển nhượng và sử dụng như một enum:

enum DataSelection { 
    case CoreDataObject(NSManagedObject) 
    case StringField(String) 
} 

var selection : DataSelection? 

selection = .CoreDataObject(someManagedObject) 

if let sel = selection { // if there's a selection at all 
    switch sel { 
     case .CoreDataObject(let coreDataObj): 
      // do what you will with coreDataObj 
     case .StringField(let string): 
      // do what you will with string 
    } 
} 

Sử dụng một enum như thế này, không cần phải lo lắng về những điều có thể được giấu bên trong Any? đó. Có hai trường hợp và chúng được ghi lại. Và tất nhiên, biến lựa chọn có thể là một tùy chọn mà không có bất kỳ lo lắng nào.

+1

Câu trả lời đúng là "tránh" bất kỳ lúc nào tất cả chi phí ". Nếu bạn đang sử dụng tùy chọn 'Bất kỳ', bạn bị vặn. – Sulthan

+2

Có, bởi vì dường như không có cách nào để ngôn ngữ phân biệt giữa 'Optional.None' được dự định để sử dụng làm giá trị thực tế hoặc để đánh dấu sự vắng mặt của một giá trị trong tùy chọn' Bất kỳ'. – Jesper

0

Có mẹo để thay thế loại Any? của tôi bằng enum nhưng tôi không thể xóa lỗi này khỏi đầu. Thay đổi cách tiếp cận của tôi không thay đổi thực tế rằng có điều gì đó không ổn với hiện tại của tôi và tôi phải tìm ra cách tôi đạt được kết quả đầu ra Optional(nil).

Tôi đã có thể tạo lại lỗi bằng cách viết bộ điều khiển chế độ xem sau trong một dự án xem một lần mới. Hãy chú ý đến chữ ký init.

import UIKit 

class Field { 
    var name: String = "Name" 
    var value: Any? 

    init(_ name: String, _ value: Any) { 
     self.name = name 
     self.value = value 
    } 
} 

class AppState { 
    var currentValue: Field? 
} 

class ViewController: UIViewController { 
    override func viewDidLoad() { 
     super.viewDidLoad() 

     let f = Field("Amount", AppState().currentValue) 
     NSLog("\(f.value)") 

    } 
} 

Nói tóm lại, tôi đã đi qua một giá trị nil (AppState().currentValue) đến một initializer chấp nhận Any, và gán nó vào một tài sản có loại là Any?. Điều buồn cười ở đây là nếu tôi trực tiếp thông qua nil thay vào đó, trình biên dịch sẽ phàn nàn:

let f = Field("Amount", nil) // Type 'Any' does not conform to protocol 'NilLiteralConvertible' 

Dường như ở đâu đó trên đường đi, kết thúc tốt đẹp Swift giá trị nil của AppState().currentValue trong một tùy chọn, do đó Optional(nil).

+0

'nil' không tồn tại dưới dạng giá trị (chỉ là từ khóa), nhưng' Optional.None' là giá trị mặc định của bất kỳ biến tùy chọn nào và nó in 'nil' khi được yêu cầu tự mô tả. – Jesper

Các vấn đề liên quan