I made a minimal reproducible code of my issue.
enum Animal {
case cat
case dog
}
protocol AdoptPet {
func petIs(pet: Animal)
}
class Delegate {
}
extension Delegate: AdoptPet {
func petIs(pet: Animal) {
print("not implemeted")
}
}
class Girl: Delegate {
}
extension Girl {
override func petIs(pet: Animal) { // overriding declarations in extensions is not supported
print(pet)
}
}
class PetCenter {
init () {
}
func setup(adpoter: Delegate){
let pet: Animal = .cat
adpoter.petIs(pet: pet)
}
}
let petCenter = PetCenter()
let adpoter: Girl = Girl()
petCenter.setup(adpoter: adpoter)
What should I change in the code to make this compile ?
You need to move both the declaration of the function and the override into the type declarations from extensions. So Delegate needs to contain the petIs implementation in its declaration and Girl needs to override the petIs function in its body as well (using the override keyword) rather than in an extension.
class Delegate: AdoptPet {
func petIs(pet: Animal) {
print("not implemeted")
}
}
class Girl: Delegate {
override func petIs(pet: Animal) {
print(pet)
}
}
class PetCenter {
init () {
}
func setup(adopter: Delegate){
let pet: Animal = .cat
adopter.petIs(pet: pet)
}
}
let petCenter = PetCenter()
let adopter = Girl()
petCenter.setup(adopter: adopter) // cat
Related
Consider the following example
class ClassA {
func createAnInstanceOfAnotherClass() -> AnotherClass {
return AnotherClass()
}
func callMeA() {
}
}
class ClassB {
func createAnInstanceOfAnotherClass() -> AnotherClass {
return AnotherClass()
}
func callMeB() {
}
}
class AnotherClass {
func doSomethingAndReturn() {
return
}
}
class MethodChain {
func methodChainTest() {
ClassA()
.createAnInstanceOfAnotherClass()
.doSomethingAndReturn() //return to ClassA
.callMeA() // call classA callMe
ClassB()
.createAnInstanceOfAnotherClass()
.doSomethingAndReturn() // return to ClassB
.callMeB() // call ClassB callMe
}
}
Is it possible for the class AnotherClass to return the instance of the class that created it?
In this example I want to use the class method doSomethingAndReturn when method chaining with both ClassA and ClassB and then contione the method chain with methods from either ClassA or ClassB
You could make AnotherClass generic with a type parameter Creator, which stores the type of its creator.
class ClassA {
func createAnInstanceOfAnotherClass() -> AnotherClass<ClassA> {
return AnotherClass(creator: self)
}
func callMeA() {
}
}
class ClassB {
func createAnInstanceOfAnotherClass() -> AnotherClass<ClassB> {
return AnotherClass(creator: self)
}
func callMeB() {
}
}
class AnotherClass<Creator: AnyObject> {
// weak to avoid retain cycles!
private weak var creator: Creator?
init(creator: Creator) {
self.creator = creator
}
func doSomethingAndReturn() -> Creator {
// assuming you always do method chaining,
// and not do something weird with the intermediate results,
// this should be safe to unwrap forcefully
creator!
}
}
The purpose of what I am trying to do is to make it possible to put objects which implements ChildOfRootClass to one array (look at AbstractClass -> children) and put at each ChildNClass instance object a link to its parent (look weak var delegate variable). So I want make type of delegate in each ChildOfRootClass generic.
Hope code will explain what exactly I have meant.
// Parent class for RootClass and Child1Class, Child2Class etc
class AbstractClass {
init() { }
init(smth: String) { }
var children = [String : ChildOfRootClass]()
func add(key: String, child: ChildOfRootClass) {
children[key] = child
}
}
Delegate protocols for each of children.
protocol ChildDelegate: class { }
protocol Child1ClassDelegate: ChildDelegate { func rr() }
protocol Child2ClassDelegate: ChildDelegate { }
class RootClass: AbstractClass {
override init() {
super.init()
}
}
extension RootClass: Child1ClassDelegate {
func rr() { }
}
Children classes.
protocol ChildOfRootClass {
associatedtype ChildOfRootClassDelegateType: ChildDelegate
weak var delegate: ChildOfRootClassDelegateType? { set get }
init(smth: String)
}
class Child1Class: AbstractClass, ChildOfRootClass {
typealias ChildOfRootClassDelegateType = Child1Delegate
weak var delegate: Child1Delegate?
required override init(smth: String) {
super.init(smth: smth)
}
}
extension Child1Class: Child2ClassDelegate { }
class Child2Class: AbstractClass/*, ChildOfRootClass*/ {
required override init(smth: String) {
super.init(smth: smth)
}
}
How I want to use it.
let root = RootClass()
let child1 = Child1Class(smth: "1")
let child2 = Child2Class(smth: "2")
child1.add(key: "child2", child: child2)
root.add(key: "child1", child: child1)
Consider the following example:
class ManObj {
func baseFunc() {
print("ManObj baseFunc")
}
}
class SubObj: ManObj {
}
protocol Model {
}
extension Model { // This is protocol extension
func someFunc() { // Protocol extension default implementation
(self as! ManObj).baseFunc()
print("Model implementation")
}
}
extension SubObj: Model {
func someFunc() {
print("SubObj Implementation")
}
}
let list = SubObj()
list.someFunc() // static dispatching
let list2: Model = SubObj()
list2.someFunc() // dynamic dispatching
The output is nicely:
SubObj Implementation
ManObj baseFunc
Model implementation
But I dislike the casting in the line (self as! ManObj).baseFunc().
In fact, I only plan to apply Model protocol to subclasses of ManObj. (But not all subclasses of ManObj are Model though!) So, I tried to change Model to:
extension Model where Self: ManObj {
func someFunc() {
self.baseFunc() // No more casting needed!
print("Model implementation")
}
}
But I'm greeted with error:
list2.someFunc() <- error: 'Model' is not a subtype of 'ManObj'
So, is there a way for me to trigger Model.someFunc from list2 after I constrain Model to where Self: ManObj?
Create an empty class just for type casting
class ManObj {
func baseFunc() {
print("ManObj baseFunc")
}
}
class SubObj: ModelCaster {
func someFunc() {
print("SubObj Implementation")
}
}
protocol Model {
}
extension Model where Self: ModelCaster { // This is protocol extension
func someFunc() { // Protocol extension default implementation
print("Model implementation")
}
}
class ModelCaster: ManObj, Model{
}
let list = SubObj()
list.someFunc() //SubObj Implementation
let list2: ModelCaster = SubObj()
list2.someFunc() //Model implementation
I have two classes that ideally would have code in their inits and deinits, e.g.:
class Tappable {
init() { Registry.register(tappable: self) }
deinit { Registry.deregister(tappable: self) }
}
class Resizable {
init() { Registry.register(resizable: self) }
deinit { Registry.deregister(resizable: self) }
}
Ideally I would inherit from both, e.g.:
class UIElement: Tappable, Resizable {}
But of course I can't in Swift. My current solution is to make one a protocol and put a note in to remind me to write init and deinit with calls to the Registry, e.g.:
//: Classes that implememt `Resizable` must call `Registry.register(resizable: self)` in all `init`s and have `deinit { Registry.deregister(resizable: self) }`.
protocol Resizable {}
class UIElement: Tappable, Resizable {
override init() {
super.init()
Registry.register(resizable: self)
}
deinit { Registry.deregister(resizable: self) }
}
Is there a better way?
You could create a composite class and store your Registry classes as variables, it could look something like this:
protocol Register {
init(_ target: UIElement)
func deregister(target: UIElement)
}
class Tappable: Register {
required init(_ target: UIElement) { Registry.register(tappable: target) }
func deregister(target: UIElement) { Registry.deregister(tappable: target) }
}
class Resizable: Register {
required init(_ target: UIElement) { Registry.register(resizable: target) }
func deregister(target: UIElement) { Registry.deregister(resizable: target) }
}
class UIElement {
var traits: [Register]!
override init() {
self.traits = [Tappable(self), Resizable(self)]
}
deinit {
self.traits.forEach { $0.deregister(self) }
}
}
This way, when deinit is called on the UIElement object, all of the traits of UIElement will be deregistered.
You can test this out in a Swift Playground by adding the following at the bottom. This will create the UIElement class, have it register for the traits, and then deallocate it and have it deregister!
var test: UIElement! = UIElement()
test = nil
You could have each protocol define a required initializer:
protocol Tappable {
init(r:Registry)
}
Then any class that inherits the protocol will have to implement that initializer, which you'd hope would remind you what needed to happen there.
That doesn't work particularly-well for UIView subclasses, which need to implement UIView's designated initializers, also.
Here's another solution, which replaces your two superclasses with a single superclass, and an OptionSet. Obviously, this gets a bit unwieldy if you need to do a lot of case-specific initialization and de-initialization, but it works okay for the example given.
class Registry {
class func register(resizeable: Any) {
}
class func register(tappable: Any) {
}
}
struct ViewTraits: OptionSet {
let rawValue: Int
init(rawValue: Int) { self.rawValue = rawValue }
static let Tappable = ViewTraits(rawValue: 1)
static let Resizeable = ViewTraits(rawValue: 2)
}
protocol Traits {
var traits:ViewTraits { get }
}
class TraitedView: NSView, Traits {
var traits:ViewTraits {
get {
fatalError("Must implement a getter for Traits")
}
}
private func register() {
if (traits.contains(.Tappable)) {
Registry.register(tappable: self)
}
if (traits.contains(.Resizeable)) {
Registry.register(resizeable: self)
}
}
override init(frame:NSRect) {
super.init(frame: frame)
register()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
register()
}
}
class MyView: TraitedView {
override var traits: ViewTraits {
get {
return [ViewTraits.Resizeable, ViewTraits.Tappable]
}
}
}
I have pinched everyones ideas in the playground below. Thanks.
var sequence = ""
enum Registry {
static func register(tappable _: Tappable) { sequence += "reg. tap.\n" }
static func deregister(tappable _: Tappable) { sequence += "dereg. tap.\n" }
static func register(resizable _: Resizable) { sequence += "reg. res.\n" }
static func deregister(resizable _: Resizable) { sequence += "dereg. res.\n" }
}
class Registrar {
init() {
if let tappable = self as? Tappable {
Registry.register(tappable: tappable)
}
if let resizable = self as? Resizable {
Registry.register(resizable: resizable)
}
}
deinit {
if let tappable = self as? Tappable {
Registry.deregister(tappable: tappable)
}
if let resizable = self as? Resizable {
Registry.deregister(resizable: resizable)
}
}
}
protocol Tappable {
func tap()
}
extension Tappable {
func tap() { sequence += "tap\n" }
}
protocol Resizable {
func resize()
}
extension Resizable {
func resize() { sequence += "resize\n" }
}
class UIElement: Registrar, Tappable, Resizable {
}
var uie: UIElement! = UIElement()
uie.tap()
uie.resize()
uie = nil
sequence // "reg. tap.\nreg. res.\ntap\nresize\ndereg. tap.\ndereg. res.\n"
I'm using Playground in Xcode, and my objects aren't being initialized with their names. I feel like it's because I'm using the convenience init incorrectly in my sublcasses, and I was wondering what is the proper way to use them in subclasses. I've read the other similar questions, but I think my question is different in the way that it has overriding inits and convenience inits.
class Animal
{
var name:String
init(name:String)
{
self.name = name
}
convenience init() { self.init(name: "") }
func speak() { }
}
class Fox: Animal
{
override init(name: String)
{
super.init(name: name)
}
convenience init() { self.init(name: "Fox") }
override func speak()
{
println("Ring")
}
}
class Cat: Animal
{
override init(name: String)
{
super.init(name: name)
}
convenience init() { self.init(name:"Cat") }
override func speak() {
println("Meow")
}
}
class Dog: Animal {
override init(name: String) {
super.init(name: name)
}
convenience init()
{
self.init(name:"Dog")
}
override func speak() {
println("Woof")
}
}
let animals = [ Dog(), Cat(), Fox()]
for animal in animals
{
animal.speak()
}
There are no errors in your code.
I think the problems is to understand how the Xcode's playground works.
probably you had pressed "show results" icon and you're watching at something like this:
but this is telling us that the "Module name" dot "Class name" of the three animals; the prefix __lldb_expr_25 ( in my picture ) is not an error but a dynamic module name that is ok in playground.
Indeed you should look at the "assistant editor":
to see the output of speck() method:
This can be even more pronounced with a slight modification to the code:
so the output is:
Let me answer according to what I understand so far -
override inits is like overriding the same to same super class init method. Here you can't add an extra behaviour as a init method parameter such as:
class Animal
{
var name:String
init(name:String)
{
self.name = name
}
func speak() { }
}
class Cat: Animal
{
override init(name: String)
{
super.init(name: name)
}
override func speak() {
println("Meow")
}
}
convenience inits is like custom init method of subclass means if you want to implement a init method into your sub-class but with some extra behaviours along with the super class init method. such as:
class Animal
{
var name:String
init(name:String)
{
self.name = name
}
func speak() { }
}
class Cat: Animal
{
var type: String = "Maine Coons"
convenience init(type:string, name: String)
{
self.type = type
self.init(name: name)
}
override func speak() {
println("Meow")
}
}
I hope it will help you.
Thanks