Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot override ReusableCellViewProtocol properties to have a custom implementation #14

Closed
BarredEwe opened this issue May 18, 2019 · 9 comments
Assignees
Labels
bug Something isn't working
Milestone

Comments

@BarredEwe
Copy link

Don't get reusableViewSource from cell. Always get from default protocol extension.

@geraldeersteling
Copy link
Contributor

I concur; overriding has no effect.

@malcommac
Copy link
Owner

There was an implementation problem with ReusableCellViewProtocol. In fact using properties Swift does not allow override them in extensions.
I've moved it to methods:

public protocol ReusableCellViewProtocol: class {
	static func reusableViewType() -> AnyObject.Type
	static func reusableViewClass() -> AnyClass
	static func reusableViewIdentifier() -> String
	static func reusableViewSource() -> ReusableViewSource

	static func registerReusableView(inTable table: UITableView?, as type: ReusableViewRegistrationType)
    static func registerReusableView(inCollection collection: UICollectionView?, as type: ReusableViewRegistrationType)
}

By default Owl provide a default implementation which uses storyboard for cells and xib for header/footer view, but now you can override it in your classes.
I'll provide a section inside the documentation before release this fix.
Thanks for your report.

@malcommac malcommac changed the title Don't get reusableViewSource Cannot override ReusableCellViewProtocol properties to have a custom implementation May 23, 2019
@malcommac malcommac self-assigned this May 23, 2019
@malcommac malcommac added the bug Something isn't working label May 23, 2019
@malcommac malcommac added this to the 1.0.4 milestone May 23, 2019
malcommac added a commit that referenced this issue May 23, 2019
@geraldeersteling
Copy link
Contributor

Nice! I was implementing it myself as functions already, but thanks for doing this :)

@malcommac
Copy link
Owner

in fact there still a problem because using methods it calls only the protocol methods not the one in cells. I'm investigating it but any help is welcome.

@geraldeersteling
Copy link
Contributor

I'll try to help; the first and least likely solution being the removal of the default implementations...forcing us to create our own sensible defaults.
I for one think this could be viable, but this is probably not something you strive for 😄.

But like I said, I'll try to help

@geraldeersteling
Copy link
Contributor

I tried messing around a little bit, but due to the nature of Swift's dispatching I'm not sure if this is going to work; currently it works because the other static vars on the protocol are derived from reusableViewClass...which is also the only one without a default implementation in the protocol.

Solutions I tried include writing overridable class functions or non-static protocol functions, all failed with "it not being possible to override declarations in extensions".

Arguably 'uglier' solutions include lifting the configuration of the cells one level higher to the TableAdapter instead of the cells themselves; using the configuration block in the TableAdapter's init to set a small struct on the adapter which contains information such as the reusableViewSource. The adapter would then call the Cell`'s static functions with the information in the provided struct.

I made some messy adjustments in a fork

Using the code in that branch I can provide the source using these lines:

let config = ReusableCellConfiguration(source: .fromXib(name: nil, bundle: nil))
let adapter = TableCellAdapter<Model, Cell>(cellConfiguration: config)

Personally I'd just go for removing the default implementation—at least for the 'source'. Maybe there is no reasonable default for where to get the cell's UI from.
Case in point; I don't use storyboards (except for some isolated and rare occasions—non table-related) and as such the default .fromStoryboard is not viable. Requiring me to override the property in all my cells either way.

@geraldeersteling
Copy link
Contributor

Ok wow, after I posted the above comment I noticed your commit...which is not far from what I was ultimately trying to do in my fork 😄

malcommac added a commit that referenced this issue May 23, 2019
malcommac added a commit that referenced this issue May 23, 2019
malcommac added a commit that referenced this issue May 23, 2019
@malcommac
Copy link
Owner

Ehehehe exactly :-)
I missed to comment it but I was updating the doc.


This is the behaviour used to load/dequeue cells and header/footer both for tables and collection views:

Entity Default Reusable Identifier Default Loading Method
Cells (UITableViewCell,UICollectionViewCell) Name of the class Load the UI with the reusable identifier from the parent table's storyboard cell prototypes list
Header/Footer View (UITableViewHeaderFooterView, UICollectionReusableView) Name of the class Attempt to load the view as the root element of the xib with the same name of the class (ie. "GroupHeaderView.xib") contained in the same bundle of the class itself.

You can however this behaviour by setting the following attributes before the adapter (TableAdapter or TableHeaderFooterAdapter for table's cells and header/footer, CollectionAdapter/CollectionHeaderFooterAdapter for collections's cell and header/footer):

  • reusableViewIdentifier: set a new reusable identifier to use.
  • reusableViewLoadSource: change the source where the view is dequeued (for cells the default value is .fromStoryboard, for header/footer is .fromXib(name:nil, bundle: nil)). Allowed values are:

By default cells or header/footer will use the name of the class itself as reusableIdentifier (for example, your cell ContactCell must have the identifier set to ContactCell).
This is an useful convention to avoid strange identifiers.

However you can still override this behaviour by setting cellReuseIdentifier (in TableAdapter or CollectionAdapter for cells) and viewReuseIdentifier (in TableHeaderFooterAdapter/CollectionHeaderFooterAdapter for header/footer).

Another interesting property is viewLoadSource; this specify where Owl must search the UI of the cell/view you are about to load. Allowed values are:

  • fromStoryboard: load from storyboard inside the table/collection's prototypes list (default value for cells).
  • fromXib(name: String?, bundle: Bundle?): load from a specific xib file in a bundle (if name is nil it uses the same filename of the cell class, ie ContactCell.xib; if bundle is nil it uses the same bundle of the class.
  • fromClass: loading from class.

The following example load a cell from an external xib with the same name of the class (ContactCell.xib) and contained in the same bundle of the cell class itself.
The same approach is valid for header/footer.

let contactAdpt = TableCellAdapter<Contact, ContactCell>()
// instead of load cell from storyboard it will be loaded by
// reading the root view inside the xib with the same name of the class
contactAdpt.viewLoadSource = .fromXib(name:nil, bundle:nil)
// optionally you can also set a custom id
contactAdpt.viewReuseIdentifier = "CustomContactCellID"
// configure...
director?.registerCellAdapter(contactAdpt)

@geraldeersteling
Copy link
Contributor

Cool! Glad you figured it out in the end :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants