Using convenience init in subclasses (Swift) - swift

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

Related

overriding declarations in extensions is not supported - swift

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

Protocol associatedtype as a type for delegate

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)

Is there a way to initialize a class in swift by using a variable which contains the name of the class?

Suppose I have a simple factory which returns various subclasses of a custom ModelObject class like:
class func testModelObject(className: String) -> ModelObject
{
let obj = // instance of the subclass of ModelObject specified by className
return obj
}
Is there a way to do this? Will Swift freak out when I try to call any methods of that object? Should I have something else for my return type?
For best type safety, you should let testModalObject to accept a meta-type like:
class ModelObject {
required init() {}
}
class Subclass: ModelObject {
required init() { super.init() }
}
func testModalObject(_ type: ModelObject.Type) -> ModelObject {
return type.init()
}
testModalObject(Subclass.self)
If you really need a string input, you will need to rely on the Objective-C runtime and do some casting (see how to create instance of a class from a string in swift 3):
#objc
class ModelObject: NSObject { // <---
required override init() {}
}
#objc(MOSubclass) // <-- tell ObjC the name is "MOSubclass" instead of "????.Subclass".
class Subclass: ModelObject {
required init() { super.init() }
}
func testModalObject(_ typeName: String) -> ModelObject? {
let cls = NSClassFromString("MO\(typeName)") as? ModelObject.Type
return cls?.init()
}
testModalObject("Subclass")!

override func in class swift

I am quite new to swift and I have a question regarding the definition of functions in a class.
I want to generate several items and give each of them a special function so I can run them by itemxy.useitem()
class item {
var name = "test"
func useitem(){
print("test")
}
}
let staff = item()
staff.name = "Staff"
staff.useitem() // prints: test
*override staff.useitem() = {print("this is a staff")}*
staff.useitem() // prints: this is a staff
how can I align a new function to my item staff?
These are not entirely swift related and are more general programming, you wont get your answers to such problems here. You should read up on basic programming principles before you tackle things further.
Having said that your problem is easily solved with Inheritance or Protocols.
Inheritance
class Item {
var name: String
init(name: String) {
self.name = name
}
func use() {
print("using a \(name)")
}
}
class Hat: Item {
override func use() {
print("I put on a \(name)")
}
}
class Pen: Item {
init() {
super.init(name: "Pen")
}
}
let pen = Pen()
pen.use()
let hat = Hat(name: "Beanie")
hat.use()
Protocol
protocol Item {
var name: String { get set }
func use()
}
extension Item {
func use() {
print("using a \(name)")
}
}
struct Pen: Item {
var name: String
init() {
self.name = "Pen"
}
}
struct Hat: Item {
var name: String
func use() {
print("I put on a \(name)")
}
}
let pen = Pen()
pen.use()
let hat = Hat(name: "Beanie")
hat.use()

Calling same property from different classes in Swift?

If I have two explicit classes that both have the same property name, is there a way to call the property without having to define which class I'm using?
class firstClass {
var name = “Name”
init…..
}
class secondClass {
var name = “Another name”
init….
}
now another function can call
//does not work... I get an error saying AnyObject doesn't have property
func printNameOf(object: AnyObject) {
println(object.name)
}
//works but my software has a lot of classes, which means a ton of code
func printNameOf(object: AnyObject) {
if object is firstClass {
println((object as firstClass).name)
}
if object is secondClass {
println((object as secondClass).name)
}
}
You could do this by creating a protocol that both your classes conform to:
protocol NameProtocol {
var name: String {get set}
}
class firstClass: NameProtocol {
var name = "Name 1"
}
class secondCLass: NameProtocol {
var name = "Name 2"
}
func printNameOf(obj: NameProtocol) {
// You know obj has property name
println(a.name)
}