2015-02-13 19 views
7

Tôi đã refactored việc của tôi với UICollectionViewCells vào sauLàm thế nào để downCast/đúc kiểu chung chung của một struct trong Swift

struct CollectionViewCellModel<T: UICollectionViewCell> { 
    let reuseIdentifier: NSString 
    let allowsSelection: Bool 

    // Optional callbacks 
    var onCreate: ((T) -> Void)?   = nil 
    var onSelection: ((T) -> Void)?   = nil 
    var onWillBeDisplayed: ((T) -> Void)? = nil 
    var onDelete: ((T) -> Void)?   = nil 

    // Create cell 
    func toCell(collectionView: UICollectionView, indexPath: NSIndexPath) -> T { 
     let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as T 
     if let onCreate = onCreate { onCreate(cell) } 
     return cell 
    } 
} 

này đã làm cho nó dễ dàng hơn cho tôi để tạo ra một danh sách các tế bào cụ thể (Đối với những thứ như các biểu mẫu) và sau đó làm việc với chúng.

Tuy nhiên, tôi tiếp tục bị vướng vào cách lưu trữ các đối tượng này. Tôi không thể downcast chúng thành CollectionViewCellModel<UICollectionViewCell> và do đó không thể lưu trữ danh sách [CollectionViewCellModel<UICollectionViewCell>

Tôi nghĩ Swift hỗ trợ truyền xuống, nhưng dường như không dành cho các loại chung?

let cell = CollectionViewCellModel<A>(...) 
let genericCell = cell as CollectionViewCellModel<UICollectionViewCell> 
// ERROR: UICollectionViewCell is not identical to A 
let genericMaybeCell = cell as? CollectionViewCellModel<UICollectionViewCell> 
// ERROR: UICollectionViewCell is not identical to A 

Tôi có phải lưu trữ chúng dưới dạng mảng Any và sau đó truyền mỗi lần hoặc tôi chỉ hiểu nhầm điều gì đó (hoặc cả hai)?


Cập nhật: tôi đã thực hiện một số công việc ở sân chơi để minh họa rõ ràng những gì tôi muốn nói:

protocol IA { 
    func name() -> String 
} 

class A:IA { func name() -> String { return "A (Base)" } } 
class B: A { override func name() -> String { return "B (Child of A)" } } 
class C: B { override func name() -> String { return "C (Child of B)" } } 

struct SA<T: A> { 
} 

let struct0: Any = SA<B>() 
// OK: yes, the struct of B is an Any! 
// but since B inherits from A, isn't it safe to 
// say that SA<B> is also of type SA<A>? 
let struct1: SA<A> = SA<B>() as SA<A> 
// NO 
// ERROR: 'B' is not identical to 'A' 
let struct1Optional: SA<A> = SA<B>() as? SA<A> 
// not even optionally? NO 
// ERROR: 'B' is not identical to 'A' 

Tôi đoán đó là không thể. Có thể trong Swift 1.3. Xem chuỗi trong nhận xét.

Cập nhật (2/17/15)


Đối với những người bạn quan tâm đến lý do tại sao tôi thậm chí làm điều này ở nơi đầu tiên, bạn phải hiểu làm thế nào tôi đang làm việc với CollectionViewControllers tôi (CVC). Tôi đã tóm tắt một CVC cơ sở để thực hiện các phương thức phổ biến mà mọi nhu cầu của màn hình. CVC này có giao thức mong đợi một Factory tạo mô hình CVC. Những mô hình này biết cách biến đổi bản thân, phản ứng với hành động và hành động rất giống một bộ điều khiển. Chúng béo & đang hoạt động. Quan điểm của tôi mặt khác đều câm lặng. Tất cả những gì họ biết phải làm là di chuyển mọi thứ xung quanh màn hình hoặc đi vào các trạng thái hiển thị khác nhau. Khi định cấu hình một ô từ CVC, bạn sẽ thực hiện những câu lệnh chuyển đổi lớn này thực sự không cho bạn biết nhiều từ góc độ dễ đọc mong đợi "định tuyến này". Nó trở nên tồi tệ hơn bạn bắt đầu cấu hình xem của bạn trong đó. Nó không phải là khủng khiếp, nhưng nói chung - với tôi - một bộ điều khiển xem kiểm soát các xem nó chịu trách nhiệm. Trong khi VC này có thể là VC mẹ của tế bào, điều này không cung cấp cho nó quyền truy cập thích hợp để thao tác nó rất nhiều. Điều này bây giờ làm cho VC của bạn làm những việc như cell.changeDisplayToActiveState(); trong ngắn hạn, nó bây giờ mang gánh nặng của việc kiểm soát các tế bào con của nó. Đây là những gì góp phần vào tất cả các "chất béo" VC ra khỏi đó. Lần đầu tiên tôi chọn để đi chệch khỏi con đường này bằng cách áp dụng mẫu VIPER, nhưng tôi thấy nó quá mức cần thiết - đặc biệt là cho một dự án mới. Tôi loại bỏ nó và bắt đầu làm việc với một CVC cơ bản. Đây hiện là như thế nào dự án của tôi hoạt động:

  • Một cơ sở CVC hy vọng một nhà máy & nhà máy hy vọng một CVC (do đó tạo điều kiện cho hai cách bắt buộc đối với các tế bào)
  • nhà máy này sản xuất tế bào & mô hình tiêu đề cho THE CVC .
  • Các mô hình này có gọi lại & dữ liệu & chức năng cấu hình được nhúng bên trong chúng.
  • Họ có thể gọi chức năng công cộng của bộ điều khiển nhìn từ những callbacks (do đó trách nhiệm tách đúng) như vc.changeDisplayState(...) hoặc changeToVc(...)
+0

Bạn đang sử dụng phiên bản Swift nào? Có 1.2 không? Và tại sao bạn thậm chí cần Generic cho điều này? Sử dụng 'UICollectionViewCell' trực tiếp nên được tốt tôi nghĩ. Và loại 'A' là gì? – sikhapol

+0

Điểm mấu chốt là 'CollectionViewCellModel ' và 'CollectionViewCellModel ' hoàn toàn không liên quan và không thể thay đổi được. Đặt cược tốt nhất của bạn có lẽ là làm cho lớp con này thành 'UICollectionViewCell' và kế thừa tất cả các ô tùy chỉnh của bạn từ đó. –

+0

Có một chủ đề về loại downcasting này trong các diễn đàn dev: https://devforums.apple.com/thread/261699?tstart=30 –

Trả lời

5

Tôi không chắc chắn chính xác những gì bạn đang sau, nhưng tôi sẽ cố gắng câu trả lời. Có lẽ bạn không quan tâm đến việc lưu trữ một bó của CollectionViewCellModel<X> 's cho một số cụ thể X, bởi vì sau đó câu trả lời cho "làm thế nào để lưu trữ chúng?" sẽ đơn giản: [CollectionViewCellModel<X>]. Vì vậy, tôi đoán bạn muốn một bạn muốn một mảng của CollectionViewCellModel<T> cho không đồng nhất T của. Cách tốt nhất để đạt được điều đó là để cho tất cả CollectionViewCellModel<T> của bạn 'sa giao thức phổ biến (hoặc lớp cơ sở, nhưng trong trường hợp của bạn chúng struct s, vì vậy không đó), một cái gì đó gần như thế này:

protocol CollectionViewCellModelType { 
    var reuseIdentifier: NSString {get} 
    var allowsSelection: Bool {get} 

    func toCell(
    collectionView: UICollectionView, indexPath: NSIndexPath 
) -> UICollectionViewCell 
} 

struct CollectionViewCellModel<T: UICollectionViewCell> 
    : CollectionViewCellModelType { 
    let reuseIdentifier: NSString 
    let allowsSelection: Bool 

    // Optional callbacks 
    var onCreate: ((T) -> Void)?   = nil 
    var onSelection: ((T) -> Void)?   = nil 
    var onWillBeDisplayed: ((T) -> Void)? = nil 
    var onDelete: ((T) -> Void)?   = nil 

    // Create cell 
    func toCell(
    collectionView: UICollectionView, indexPath: NSIndexPath 
) -> UICollectionViewCell { 
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(
     reuseIdentifier, forIndexPath: indexPath) as! T 

    if let onCreate = onCreate { onCreate(cell) } 
    return cell 
    } 
} 

var a: [CollectionViewCellModelType] = [] // put them in here 

Hy vọng này giúp,

Dave

+0

Phát ngay.Tôi muốn có một bộ sưu tập không đồng nhất của các mô hình tế bào. Ví dụ 'EditTextFieldCVModel '; do đó, mô hình sẽ chịu trách nhiệm giữ các dữ liệu cần thiết và định cấu hình chế độ xem. Cách tiếp cận chung tương tự giữ cho onSelect và tất cả điều đó. Tất cả các phương thức ủy nhiệm trở thành một lớp lót nơi tất cả các hành động có liên quan (dữ liệu, cấu hình, gọi lại, vv) được tìm thấy trong CVModel. Ty! – joslinm

+0

Trong trường hợp của tôi, tôi đã có thể thoát khỏi bằng cách sử dụng 'enum' với các giá trị liên quan để thay thế. Đã có kết quả tương tự. – Mazyod

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