2015-02-08 22 views
7

Tôi nhận được thông báo lỗi "Đã tìm thấy bất ngờ nil trong khi mở một Optional" từ Swift, với lớp bên dưới. Lỗi này xảy ra trên dòng:Bất ngờ tìm thấy nil khi unwrapping một giá trị tùy chọn swift

(cell.contentView.viewWithTag(1) as UILabel).text = object["firstName"] as? String 

Tôi có một lớp tế bào tùy chỉnh với 2 UILabels tagged 1 và 2, các cửa hàng được thiết lập

import UIKit 
    import Foundation 

    class dictionaryTableViewController: UIViewController,  UITableViewDelegate, UITableViewDataSource{ 

    var objects = NSMutableArray() 
    var dataArray = [["firstName":"Debasis","lastName":"Das","email":"[email protected]"],["firstName":"John","lastName":"Doe","email":"[email protected]"],["firstName":"Jane","lastName":"Doe","email":"[email protected]"],["firstName":"Mary","lastName":"Jane","email":"[email protected]"]] 

    @IBOutlet 
    var tableView: UITableView! 

    var items: [String] = ["We", "Heart", "Swift"] 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.tableView.registerClass(UITableViewCell.self, forCellReuseIdentifier: "MyCell") 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
    } 


    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return dataArray.count;//self.items.count; 
    } 

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     //var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell 
     //cell.textLabel?.text = self.items[indexPath.row] 
     //return cell 
     let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as UITableViewCell 
     let object = dataArray[indexPath.row] as NSDictionary 
     (cell.contentView.viewWithTag(1) as UILabel).text = object["firstName"] as? String 
     (cell.contentView.viewWithTag(2) as UILabel).text = object["lastName"] as? String 
     return cell 
    } 

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 

     println("You selected cell #\(indexPath.row)!") 

    } 

} 
+1

Tôi nghĩ rằng vấn đề là với 'viewWithTag (_ :)', mà trả về một 'UIView '(Tùy chọn' UIView')?. Nếu nó là 'nil', thì truy cập thuộc tính' text' gây ra sự cố. Cố gắng thay đổi mã thành 'if let tag1 = cell.contentView.viewWithTag (1) thành UILabel {...}' và đặt điểm ngắt ở đó để xem điều gì xảy ra. – Romain

Trả lời

20

Nếu bạn muốn sử dụng một cách bố trí di động tùy chỉnh, tôi sẽ đề nghị

  1. Subclass UITableViewCell:

    // CustomTableViewCell.swift 
    
    import UIKit 
    
    class CustomTableViewCell: UITableViewCell { 
    
        @IBOutlet weak var firstNameLabel: UILabel! 
        @IBOutlet weak var lastNameLabel: UILabel! 
    
    } 
    
  2. Tạo xem bảng trong kịch bản này. Thêm nguyên mẫu ô vào bảng trong bảng phân cảnh. Thiết kế nguyên mẫu ô đó (thêm bất kỳ nhãn nào bạn muốn).

  3. Chỉ định trình nhận dạng bảng phân cảnh cho mẫu thử nghiệm ô là bất kỳ thứ gì bạn muốn (MyCell trong ví dụ của bạn).

    enter image description here

  4. Xác định lớp cơ sở cho mẫu di động được, trong ví dụ này, CustomTableViewCell:

    enter image description here

  5. Treo lên các tài liệu tham khảo IBOutlet giữa nguyên mẫu di động của bạn và UITableViewCell lớp con của bạn .

    enter image description here

    Thông báo đạn rắn bên trái của các tài liệu tham khảo IBOutlet. Điều đó cho thấy rằng ổ cắm được nối đúng cách.

  6. Triển khai cellForRowAtIndexPath trong nguồn dữ liệu của bạn, ví dụ: trong Swift 3:

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
        let cell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! CustomTableViewCell 
    
        let person = dataArray[indexPath.row] 
    
        cell.firstNameLabel.text = person["firstName"] 
        cell.lastNameLabel.text = person["lastName"] 
    
        return cell 
    } 
    

    Hoặc trong Swift 2:

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
        let cell = tableView.dequeueReusableCellWithIdentifier("MyCell", forIndexPath: indexPath) as! CustomTableViewCell 
    
        let person = dataArray[indexPath.row] 
    
        cell.firstNameLabel.text = person["firstName"] 
        cell.lastNameLabel.text = person["lastName"] 
    
        return cell 
    } 
    
  7. Lưu ý, nếu sử dụng nguyên mẫu di động, bạn làm không muốn gọi registerClass trong viewDidLoad. Bảng phân cảnh sẽ tự động đăng ký lớp tùy chỉnh của bạn với số nhận dạng được sử dụng lại cho bạn (vì những gì bạn đã làm trong bước 3 và 4).

+0

Cảm ơn, đây là câu trả lời hay nhất! – Jhonny

+0

Cảm ơn, điều này đã cho tôi kể từ khi tôi được sử dụng để làm xibs cho các tế bào tùy chỉnh: 7. Lưu ý, nếu sử dụng nguyên mẫu tế bào, bạn không muốn gọi registerClass trong viewDidLoad. Bảng phân cảnh sẽ tự động đăng ký lớp tùy chỉnh của bạn với số nhận dạng được sử dụng lại cho bạn (vì những gì bạn đã làm trong bước 3 và 4). –

+2

tôi gặp lỗi "lỗi nghiêm trọng: bất ngờ tìm thấy nil khi mở một giá trị Tùy chọn" –

3

EDIT2: Giải pháp này là có thể tốt hơn cho mục đích của bạn. Với điều này, bạn tạo ra lớp của riêng bạn cho UITableViewCell của riêng bạn và sử dụng nó với mô hình tái sử dụng. Bình luận là trong các mã:

class dictionaryTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{ 

    // The data 
    var dataArray = [["firstName":"Debasis","lastName":"Das","email":"[email protected]"],["firstName":"John","lastName":"Doe","email":"[email protected]"],["firstName":"Jane","lastName":"Doe","email":"[email protected]"],["firstName":"Mary","lastName":"Jane","email":"[email protected]"]] 

    // The outlet to your tableview in the ViewController in storyboard 
    @IBOutlet var tableView: UITableView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     // Create a nib for reusing 
     let nib = UINib(nibName: "MyCell", bundle: nil) 
     // Register the nib for reusing within the tableview with your reuseidentifier 
     tableView.registerNib(nib, forCellReuseIdentifier: "MyCell") 

     // Set delegate and datasource to self (you can do that in interface builder as well 
     tableView.delegate = self 
     tableView.dataSource = self 
    } 

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return dataArray.count; // return the number of datasets 
    } 

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 

     // create a reusable cell with the reuse identifier you registered in viewDidLoad and cast it to MyCell 
     let cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as MyCell 
     let object = dataArray[indexPath.row] as NSDictionary 

     // set the strings matching your array 
     cell.label1.text = object["firstName"] as? String 
     cell.label2.text = object["lastName"] as? String 

     // return the cell 
     return cell 

    } 

    // some example for the delegate 
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
     println("You selected cell #\(indexPath.row)!") 
    } 


} 


// class for you own UITableViewCell 
// has own xib file 
class MyCell: UITableViewCell { 

    // two outlets representing two labels in the xib file 
    @IBOutlet private weak var label1: UILabel! 
    @IBOutlet private weak var label2: UILabel! 
} 

Để làm việc này bạn phải tạo một xib file với tên bên phải (trong trường hợp này MyCell). Nó nên một cái gì đó tương tự như sau:

enter image description here

Điều rất quan trọng để thiết lập các lớp của giao diện tùy chỉnh và các cửa hàng.

------------------------------------- GIẢI PHÁP KHÁC ------- -------------------------------

EDIT: Khi tôi thấy nó, bạn không khởi tạo lớp của riêng bạn ' MyCell´ nhưng lớp của Apple ´UITableViewCell´ với reuseIdentifier ´MyCell´. Vì vậy, đó là giải pháp cho việc sử dụng UITableViewCell:

Dòng (cell.contentView.viewWithTag(1) as UILabel) không chỉ là một diễn viên cho một lớp cụ thể mà nó còn mở khóa tùy chọn (UIView). Bạn làm điều đó trong các trường hợp khác với '!'. Vì vậy, vấn đề là: bạn đang tạo ra một thể hiện của UITableViewCell, một lớp Apple tạo ra. Bạn muốn nhận được các bản xem trước bên trong chế độ xem đó với các thẻ cụ thể. Làm thế nào để bạn biết táo đã cho họ những thẻ này? Những gì bạn thực sự muốn là tạo ra một thể hiện của UITableViewCell với một phong cách đặc biệt và thiết lập các giá trị của textLabels như thế này:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     // Create an instance of UITableViewCell. Style is .Subtitle but could be others as well 
     var cell = tableView.dequeueReusableCellWithIdentifier("MyCell") as? UITableViewCell 
    let object = dataArray[indexPath.row] as NSDictionary 

    // set the strings matching your array 
    cell?.textLabel?.text = object["firstName"] as? String 
    cell?.detailTextLabel?.text = object["lastName"] as? String 

    // return the cell 
    return cell! 
    } 
+0

anh ấy đang khởi tạo 'MyCell' - không phải lớp của apple - vì vậy các thẻ của anh ấy có thể ở đó :) –

+0

Có, tôi đã đặt thẻ của mình nhưng vẫn làm việc này để cảm ơn bạn! – Jhonny

+1

Ông đặt ´MyCell´ là một reuseIdentifier cho lớp UITableViewCell vì vậy ông đang khởi tạo UITableViewCell. Nếu nó hoạt động, vui lòng kiểm tra câu trả lời đúng để những người khác đang tìm kiếm vấn đề này có thể thấy câu trả lời .. – Ben

0

Tất cả tôi phải làm là:

cell.subviews[0].subviews[0].viewWithTag(//your tag//) 
Các vấn đề liên quan