Registering UITableViewCell using ReusableKit swift - swift

I am trying to build generic getAll method will which just return instances of Reusable cells.
By creating that I don't have to register the cells manually I can just add it to the array and in the registerCellsFromReusable() it will be registered.
enum Reusable {
static let listOptionTableCell = ReusableCell<ListOptionTableCell>(nibName: "ListOptionTableCell")
static let seperatorTableCell = ReusableCell<SeperatorTableCell>(nibName: "SeperatorTableCell")
static func getAll<T>() -> [ReusableCell<T>] where T : UITableViewCell {
return [listOptionTableCell, seperatorTableCell]
}
}
override func viewDidLoad() {
super.viewDidLoad()
registerCellsFromReusable()
}
private func registerCellsFromReusable() {
Reusable.getAll().forEach { tableView.register($0) }
}
Cool stuff but I don't know why I am getting the below issue even though ListOptionTableCell & SeperatorTableCell inherits from UITableViewCell
Note: I am using ReusableKit to do this.

I have no in depth knowledge of the ReusableKit framework, but in order to make this work you have to apply some form of type erasure. Swift is unable to create a properly typed collection of different types (due to the generics used here), so we have to find a type to which we can convert them to match your needs. In this case, this would be ReusableCell<UITableViewCell>. We only care that T in ReusableCell inherits from UITableViewCell in the end.
// Create an extension on ReusableCell to type erase it
extension ReusableCell {
var asTypeErasedReusableCell: ReusableCell<UITableViewCell> {
ReusableCell<UITableViewCell>(nibName: nibName)
}
}
enum Reusable {
static let listOptionTableCell = ReusableCell<ListOptionTableCell>(nibName: "ListOptionTableCell")
static let seperatorTableCell = ReusableCell<SeperatorTableCell>(nibName: "SeperatorTableCell")
static func getAll() -> [ReusableCell<UITableViewCell>] {
[
listOptionTableCell.asTypeErasedReusableCell,
seperatorTableCell.asTypeErasedReusableCell
]
}
}
Note that this is a very simple implementation of type erasure. There are way more sophisticated ways of achieving this.

Related

How do I check the class of an instance that conforms to a protocol in swift?

I'm trying to check the class of an instance which conforms to a protocol.
I have a protocol.
protocol ToolbarProtocol {
func show()
func hide()
}
I have a class which conforms to that protocol.
class GameToolbar: ToolbarProtocol {
...
}
I have a manager class I createed to manage my toolbars.
class ToolbarManager {
var existingToolbars: [Game.rotation: Array<ToolbarProtocol>]
}
In this manager, I have a function that wants to find the first instance of a specific type of toolbar.
func getDebugToolbar() -> ToolbarProtocol? {
return existingToolbars[.east]?.first(where: { (toolbar: ToolbarProtocol) -> Bool in
toolbar.isKind(of: GameToolbar.self) //This line causes an error because .isKind is not a member of ToolbarProtocol
})
}
I can't call isKind(of) on toolbar, which previously worked when my toolbars were a different kind of class provided by an external library (which I'm trying to remove from my codebase because I want different functionality).
I tried making my protocol extend AnyObject, but I think that's implicit anyway, and it had no effect.
How can I check an array of instances which conform to a given protocl, to check for specific class types?
I think you would need to attempt to cast it, like
if let vc = toolbar as? GameToolbar {}
In your case, you might need something like this:
func getDebugToolbar() -> ToolbarProtocol? {
return existingToolbars[.east]?.first(where: { (toolbar: ToolbarProtocol) -> Bool in
let _ = toolbar as? GameToolbar
})
}

In Swift, can you write an extension which returns a typed instance of the class the extension is on?

This is one of those things that seems simple enough, but doesn't work as you'd expect.
I'm working on a 'fluent/chaining'-style API for my classes to allow you to set properties via functions which can be chained together so you don't have to go crazy with initializers. Plus, it makes it more convenient when working with functions like map, filter and reduce which share the same kind of API.
Consider this RowManager extension...
extension RowManager
{
#discardableResult
public func isVisible(_ isVisible:Bool) -> RowManager
{
self.isVisible = isVisible
return self
}
}
This works exactly as one would expect. But there's a problem here... if you're working with a subclass of RowManager, this downcasts the object back to RowManager, losing all of the subclass-specific details.
"No worries!" I thought. "I'll just use Self and self to handle the type!" so I changed it to this...
extension RowManager
{
#discardableResult
public func isVisible(_ isVisible:Bool) -> Self // Note the capitalization representing the type, not instance
{
self.isVisible = isVisible
return self // Note the lowercase representing the instance, not type
}
}
...but that for some reason won't even compile giving the following error...
Command failed due to signal: Segmentation fault: 11
UPDATE
Doing more research, this seems to be because our code both is in, and also uses, dynamic libraries. Other questions here on SO also talk about that specific error in those cases. Perhaps this is a bug with the compiler because as others have correctly pointed out, this code works fine in a stand-alone test but as soon as the change is made in our code, the segmentation fault shows up.
Remembering something similar with class functions that return an instance of that type, I recalled how you had to use a private generic function to do the actual cast, so I tried to match that pattern with the following...
extension RowManager
{
#discardableResult
public func isVisible(_ isVisible:Bool) -> Self // Note the capitalization
{
self.isVisible = isVisible
return getTypedSelf()
}
}
private func getTypedSelf<T:RowManager>() -> T
{
guard let typedSelfInstance = self as? T
else
{
fatalError() // Technically this should never be reachable.
}
return typedSelfInstance
}
Unfortunately, that didn't work either.
For reference, here's the class-based code I attempted to base that off of (className is another extension that simply returns the string-representation of the name of the class you called it on)...
extension UITableViewCell
{
/// Attempts to dequeue a UITableViewCell from a table, implicitly using the class name as the reuse identifier
/// Returns a strongly-typed optional
class func dequeue(from tableView:UITableView) -> Self?
{
return self.dequeue(from:tableView, withReuseIdentifier:className)
}
/// Attempts to dequeue a UITableViewCell from a table based on the specified reuse identifier
/// Returns a strongly-typed optional
class func dequeue(from tableView:UITableView, withReuseIdentifier reuseIdentifier:String) -> Self?
{
return self.dequeue_Worker(tableView:tableView, reuseIdentifier:reuseIdentifier)
}
// Private implementation
private class func dequeue_Worker<T:UITableViewCell>(tableView:UITableView, reuseIdentifier:String) -> T?
{
return tableView.dequeueReusableCell(withIdentifier: reuseIdentifier) as? T
}
}
At WWDC Apple confirmed this was a Swift compiler issue that something else In our codebase was triggering, adding there should never be a case where you get a Seg11 fault in the compiler under any circumstances, so this question is actually invalid. Closing it now, but I will report back if they ever address it.

Extending a class with instance method

I'm trying to extend the functionality of a existing type in Swift. I want to use dot syntax to call the methods on the type.
I want to say:
existingType.example.someMethod()
existingType.example.anotherMethod()
I'm currently using an extension like so:
extension ExistingType {
func someMethod() {
}
func anotherMethod() {
}
}
existingType.someMethod()
existingType.anotherMethod()
Doing this will expose too many functions. So, I want to write these methods in a class, and just extend the ExistingType to use an instance of the class. I'm not sure the right way to go about this.
if I were actually implementing the existing type, I would do the following:
struct ExistingType {
var example = Example()
}
struct Example {
func someMethod() {
}
func anotherMethod() {
}
}
Allowing me to call the methods by:
let existingType = ExistingType()
existingType.example.someMethod()
The issue is I'm not implementing the type, because it already exists. I just need to extend it.
It looks like you are trying to add another property example the existing class ExistingType and call methods of that property. You cannot add properties in extensions, though. The only way to add another property to the existing class is to subclass it.
You can create a new struct.
struct NewType {
let existingType: ExistingType
func someMethod() {
}
func anotherMethod() {
}
}

How to constraint generic type to another generic type in Swift?

I'd like to do something like this:
class Config<T> {
func configure(x:T)
// constraint B to be subclass of A
class func apply<A,B:A>(c:Config<A>, to:B) {
c.configure(to)
}
}
So later, for example, I can apply a Config to a UILabel:
class RedViewConfig<T:UIView> : Config<T> {
func configure(x:T) {
x.backgroundColor = .redColor();
}
}
let label = UILabel()
Config.apply(RedViewConfig(), to:label)
Or extend Config classes:
class RedLabelConfig<T:UILabel> : RedViewConfig<T> {
func configure(x:T) {
super.configure(x)
x.textColor = .redColor();
}
}
Config.apply(RedLabelConfig(), to:label)
I tried to do it, but I couldn't constraint classes. So I tried with protocols and associated types, but when subclassing I found problems (like this) when overriding the associated type.
Do you actually need the generic parameter B? If your argument to: was typed as A as well, it could be any subtype of A. Like such:
class View {}
class LabelView : View {}
class Config<T> {
func configure(x:T) { print ("Configured: \(x)") }
}
func applyConfig<A> (c:Config<A>, to:A) {
c.configure(to)
}
applyConfig(Config<View>(), to: LabelView())
Classes make this way too complicated. Inheritance is almost always a bad idea in Swift if you can possibly avoid it.
Structs, though closer, still make this a bit over-complicated and restrictive.
Really, these configurators are just functions. They take a thing and they do something to it, returning nothing. They're just T -> Void. Let's build a few of those.
func RedViewConfig(view: UIView) { view.backgroundColor = .redColor() }
func VisibleConfig(view: UIView) { view.hidden = false }
And we can use them pretty easily:
let label = UILabel()
VisibleConfig(label)
We can compose them (like super, but without the baggage) if their types are compatible:
func RedLabelConfig(label: UILabel) {
RedViewConfig(label)
label.textColor = .redColor()
}
We can pass them around in data structures, and the compiler will apply the right covariance for us:
let configs = [RedLabelConfig, VisibleConfig]
// [UILabel -> ()]
// This has correctly typed visibleConfig as taking `UILabel`,
// even though visibleConfig takes `UIView`
// And we can apply them
for config in configs { config(label) }
Now if we want other syntaxes, we can build those pretty easily too. Something more like your original:
func applyConfig<T>(f: T -> Void, to: T) {
f(to)
}
applyConfig(VisibleConfig, to: label)
or even closer to your original:
struct Config {
static func apply<T>(config: T -> Void, to: T) { config(to) }
}
Config.apply(VisibleConfig, to: label)
The point is that just using functions here makes everything very flexible without adding any of the complexity of class inheritance or even structs.

Swift Generics and Protocol Extensions

I have a protocol Reusablethat has a static function static func reuseId() -> String and a protocol extension that defines the default implementation for the function. Then, I implemented a extension on UITableViewCell to conform to the Reusable protocol. I can now use the function on my TableViewCells without a problem: SomeTableViewCell.reuseId().
The Problem I have is with Generics. I have a generic class that has a generic parameter of the type UITableViewCell:
internal class SomeClass<CellType: UITableViewCell>: NSObject {
...
}
I want to be able to use the function specified in Reusable in my generic class on CellType but unfortunately this does not work as expected. The compiler always generates the error Type 'CellType' has no member 'reuseId'.
Does anybody know why this is happening? Is there a workaround?
I am using Xcode 7.0 with Swift 2.0.
Greetings from Germany
UPDATE: Here is some sample code that better shows my problem:
import UIKit
protocol Reusable {
static func reuseId() -> String
}
extension Reusable {
static func reuseId() -> String {
return String(self).componentsSeparatedByString(".").last!
}
}
extension UITableViewCell: Reusable { }
class SomeGenericClass<CellType: UITableViewCell> {
func someFunction() {
let reuseIdentifier = CellType.reuseId()
}
}
This Code will generate the above error but I do not quite understand why this happens. I think the main difference to the sample code that jtbandes posted is that I use a static function.
UPDATE: The issue is fixed in Xcode 8.3 beta 2. The sample code above now works as expected (after migrating it to Swift 3 of course).
That's an interesting problem. Your code seems like it should work; you might want to file an enhancement request.
Here's a workaround that seems to work correctly:
class SomeGenericClass<CellType: Cell> {
func someFunction() {
let reuseIdentifier = (CellType.self as Reusable.Type).reuseId()
}
}
Another (workaround) way to get what you need:
class GenericExample<CellType:UITableViewCell where CellType:Reusable>
{
func test() -> String {
return CellType.reuseId()
}
}
GenericExample<UITableViewCell>().test() // returns "UITableViewCell"
GenericExample<MyCell>().test() // returns "MyCell"