2015-11-19 19 views
8

Tôi muốn tạo bộ điều khiển xem có thể tái sử dụng UsersViewControllerBase.Làm thế nào để phân lớp UIViewController tùy chỉnh trong Swift?

UsersViewControllerBase kéo dài UIViewController, và thực hiện hai đại biểu (UITableViewDelegate, UITableViewDataSource), và có hai quan điểm (UITableView, UISegmentedControl)

Mục đích là để kế thừa thi hành UsersViewControllerBase và tùy chỉnh các mục phân đoạn kiểm soát phân đoạn trong UsersViewController lớp học.

class UsersViewControllerBase: UIViewController, UITableViewDelegate, UITableViewDataSource{ 
    @IBOutlet weak var segmentedControl: UISegmentedControl! 
    @IBOutlet weak var tableView: UITableView! 
    //implementation of delegates 
} 

class UsersViewController: UsersViewControllerBase { 
} 

Các UsersViewControllerBase hiện diện trong kịch bản và tất cả các cửa hàng được kết nối, nhận dạng được chỉ định.

Câu hỏi đặt ra là làm thế nào tôi có thể init UsersViewController để kế thừa toàn bộ các quan điểm và chức năng của UsersViewControllerBase

Khi tôi tạo ra các thể hiện của UsersViewControllerBase mọi thứ hoạt động

let usersViewControllerBase = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("UsersViewControllerBase") as? UsersViewControllerBase 

Nhưng khi tôi tạo ra các thể hiện của UsersViewController Tôi nhận được nil cửa hàng (Tôi đã tạo đơn giản UIViewController và gán lớp UsersViewController cho nó trong bảng phân cảnh)

let usersViewController = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("UsersViewController") as? UsersViewController 

Dường như lượt xem không được kế thừa.

Tôi mong chờ phương pháp init trong UsersViewControllerBase mà được điều khiển với quan điểm và các cửa hàng từ kịch bản:

class UsersViewControllerBase: UIViewController, UITableViewDelegate, UITableViewDataSource{ 
     @IBOutlet weak var segmentedControl: UISegmentedControl! 
     @IBOutlet weak var tableView: UITableView! 
     init(){ 
     let usersViewControllerBase = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle()).instantiateViewControllerWithIdentifier("UsersViewControllerBase") as? UsersViewControllerBase 
     self = usersViewControllerBase //but that doesn't compile 
     } 
    } 

Và tôi sẽ init UsersViewController:

let usersViewController = UsersViewController() 

Nhưng tiếc là điều đó không làm việc

+0

Vâng, chúng _are_ được kế thừa, vì vậy có điều gì đó không ổn (như có thể thiết lập cảnh trong kịch bản của bạn). Bạn có nhớ _connect_ những cửa hàng đó không? – matt

+0

không có tôi đã không kết nối các cửa hàng trong UsersViewController bởi vì tôi nghĩ rằng họ đã được kết nối (vì vậy có thể được thừa hưởng) trong UsersViewControllerBase. Và ý tưởng không phải là để tái tạo cùng một cái nhìn trong UsersViewController nhưng kế thừa nó từ UsersViewControllerBase – Alex

Trả lời

3

Khi bạn tạo một điều khiển xem qua instantiateViewControllerWithIdentifier, quá trình này về cơ bản là như sau:

  • nó tìm thấy một cảnh với định danh đó;
  • nó xác định lớp cơ sở cho cảnh đó; và
  • nó trả về một phiên bản của lớp đó.

Và sau đó, khi bạn lần đầu tiên truy cập vào view, nó sẽ:

  • tạo hệ thống phân cấp xem như được nêu trong đó cảnh kịch bản; và
  • kết nối các cửa hàng.

(Quá trình này thực sự phức tạp hơn thế, nhưng tôi đang cố gắng để giảm nó đến các yếu tố quan trọng trong công việc này.)

Hàm ý của công việc này là các cửa hàng và các lớp cơ sở được xác định bằng mã nhận diện cốt truyện duy nhất mà bạn chuyển đến instantiateViewControllerWithIdentifier. Vì vậy, đối với mỗi lớp con của lớp cơ sở của bạn, bạn cần một cảnh kịch bản riêng biệt và đã kết nối các cửa hàng với lớp con cụ thể đó.

Có một cách tiếp cận sẽ thực hiện những gì bạn đã yêu cầu. Thay vì sử dụng khung cảnh cho bộ điều khiển chế độ xem, bạn có thể thay thế bộ điều khiển chế độ xem loadView (không bị nhầm lẫn với viewDidLoad) và tạo lập trình phân cấp chế độ xem theo yêu cầu của lớp trình điều khiển chế độ xem. Apple đã từng có một giới thiệu tuyệt vời về quy trình này trong Hướng dẫn lập trình bộ điều khiển xem cho iOS, nhưng đã từ bỏ cuộc thảo luận đó nhưng vẫn có thể tìm thấy trong số legacy documentation.

Có nói rằng, cá nhân tôi sẽ không bị ép buộc quay trở lại thế giới cũ của chế độ xem được lập trình cũ trừ khi có một trường hợp rất hấp dẫn cho điều đó. Tôi có khuynh hướng từ bỏ cách tiếp cận lớp con của bộ điều khiển xem và áp dụng một thứ gì đó giống như một lớp đơn (có nghĩa là tôi quay lại thế giới của bảng phân cảnh) và sau đó chuyển nó một số định danh quy định hành vi tôi muốn từ trường hợp cụ thể đó cảnh đó. Nếu bạn muốn giữ một số thanh lịch OO về điều này, bạn có thể khởi tạo các lớp tùy chỉnh cho nguồn dữ liệu và ủy nhiệm dựa trên một số thuộc tính mà bạn đặt trong lớp trình điều khiển dạng xem này.

Tôi muốn có xu hướng đi xuống con đường này nếu bạn cần hành vi điều khiển chế độ xem động thực sự, thay vì phân cấp chế độ xem được tạo theo chương trình. Hoặc, thậm chí đơn giản hơn, hãy tiếp tục và áp dụng cách tiếp cận phân lớp bộ điều khiển xem ban đầu của bạn và chỉ chấp nhận rằng bạn sẽ cần các cảnh riêng biệt trong bảng phân cảnh cho mỗi lớp con.

+0

Giải thích rất tốt, cảm ơn rất nhiều. Tôi thích sử dụng "cách tiếp cận phân lớp" và các cảnh riêng biệt cho mọi lớp con. Ít nhất tôi tránh trùng lặp mã và sao chép các cảnh bằng nhau trong bảng phân cảnh không phải là vấn đề lớn. – Alex

+0

Trong trường hợp bạn vẫn muốn có khả năng phân lớp VC với các cửa hàng, bạn có thể thực hiện phương pháp .xib. Tạo một .xib với tất cả các giao diện và cửa hàng và tạo một lớp cho nó. Bây giờ, 'UserViewControllerBase' sẽ thêm .xib này vào' self.view' bên trong 'viewDidLoad()' và có chế độ xem tùy chỉnh làm thành viên. sau đó, 'UsersViewController' sẽ kế thừa lớp cơ sở và sẽ có khung nhìn tùy chỉnh từ lớp cha của nó, và nó sẽ có quyền truy cập vào tất cả các cửa hàng thông qua chế độ xem tùy chỉnh thành viên. Cá nhân, tôi không yêu giải pháp này, nhưng tốt hơn là sao chép VC của bảng phân cảnh – gutte

0

Vấn đề là bạn đã tạo một cảnh trong bảng phân cảnh, nhưng bạn không cung cấp chế độ xem của trình điều khiển xem nect bất kỳ cửa hàng, vì vậy giao diện trống.

Nếu mục tiêu của bạn là sử dụng lại bộ sưu tập chế độ xem và xem phụ kết hợp với các trường hợp của một số lớp trình điều khiển chế độ xem khác nhau, cách đơn giản nhất, nếu bạn không muốn tạo chúng trong mã, hãy đặt chúng trong .xib tệp và tải nó trong mã sau quá trình xem lượt xem của chính trình điều khiển xem (ví dụ: trong viewDidLoad). Nhưng nếu mục tiêu chỉ là "tùy chỉnh các mục được phân đoạn của điều khiển phân đoạn" trong các trường hợp khác nhau của bộ điều khiển xem này, cách tiếp cận đơn giản nhất là có một lớp trình điều khiển chế độ xem và một thiết kế giao diện tương ứng và thực hiện tùy chỉnh trong mã . Tuy nhiên, bạn có thể chỉ tải kiểm soát được phân đoạn đó từ .xib riêng trong mỗi trường hợp, nếu điều quan trọng là bạn thiết kế nó một cách trực quan.

5

Vì vậy, bạn có lớp cơ sở của bạn:

class UsersViewControllerBase: UIViewController, UITableViewDelegate, UITableViewDataSource { 
    @IBOutlet weak var segmentedControl: UISegmentedControl! 
    @IBOutlet weak var tableView: UITableView! 
    //implementation of delegates 
} 

Và phân lớp của bạn:

class UsersViewController: UsersViewControllerBase { 
    var text = "Hello!" 
} 

Để sử dụng đúng cách các lớp con, bạn không cần phải làm (một cái gì đó tương tự) này:

class TestViewController: UIViewController { 
    ... 
    func doSomething() { 
     let storyboard = UIStoryboard(name: "Main", bundle: nil) 
     //Instantiate as base 
     let usersViewController = storyboard.instantiateViewControllerWithIdentifier("UsersViewControllerBase") as! UsersViewControllerBase 
     //Replace the class with the desired subclass 
     object_setClass(usersViewController, UsersViewController.self) 
     //But you also need to access the instance variable 'text', so: 
     let subclassObject = usersViewController as! UsersViewController 
     subclassObject.text = "Hello! World." 
     //Use UsersViewController object as desired. For example: 
     navigationController?.pushViewController(subclassObject, animated: true) 
    } 
} 
Các vấn đề liên quan