5

I'm trying to figure out the best pattern to work with objects in Swift.

i think i got it right with the initializers, both convenience and default... but what happen with the class factory methods?

I tried to create a simple class Person and a subclass Student, with few properties and methods. is it the most correct way to do it?

   class Person{
    
    var _name: String
    var _surname: String
    var _dateOfBirthday: String
    var _phoneNumb: [String]
    
    init(name:String, surname:String, dateOfBirthday:String, phone:[String]){
        self._name = name
        self._surname = surname
        self._dateOfBirthday = dateOfBirthday
        self._phoneNumb = phone
    }
    
    convenience init() {
        self.init(name:"",surname:"",dateOfBirthday:"", phone:[])
    }
    
    convenience init(name:String){
        self.init(name:name,surname:"",dateOfBirthday:"", phone:[])
    }
    
    
}



class Student:Person{
    
    var _studentId:Int
    
    init(name: String, surname: String, dateOfBirthday: String, phone: [String], id:Int) {
        self._studentId = id
        super.init(name: "", surname: "", dateOfBirthday: "", phone: [])
    }
    
    convenience init(){
        self.init(name: "", surname: "", dateOfBirthday: "", phone: [], id:0)
    }
    
    convenience init(name:String){
        self.init(name:name,surname:"",dateOfBirthday:"", phone:[], id:0)
    }
    
}

what if i want to add a class factory method? would it be something like this or i'm doing it wrong?

class func Person() -> Person {
 var x = Person()
 x._telephoneNumber = [String]() // is this needed? or i can initialize it later?
 return x
}

class func PersonWithName(name:String) -> Person {
 var x = Person(name:name, surname:"", dateOfBirthday:"", telephoneNumber:[])
 return x
}

is this correct? why would it be better to use the init instead of the class factory?

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Swifterino
  • 91
  • 1
  • 1
  • 5

2 Answers2

5

is this correct? why would it be better to use the init instead of the class factory?

Why would you create a "class factory" if you can use init? init is idiomatic Swift way of creating new objects of a class.

Adding convenience initializers is the right choice in most cases when you want to add a shortcut to class's main (designated) initializer. However, in your case, they are completely unnecessary, because Swift supports default argument values.

Just define your initializer like so:

init(name:String = "", surname:String = "", dateOfBirthday:String = "", phone:[String] = []) { ... }

This way, you can invoke it as Person() or Person(name: "Andrew") or with any other combination of arguments.

EDIT:

As a side note, prefixing instance variables with an underscore generally doesn't seem to be idiomatic Swift. It's okay to omit the underscore and use self. to disambiguate between local and instance variables:

self.name = name
self.surname = surname
self.dateOfBirthday = dateOfBirthday
self.phoneNumb = phone
radex
  • 6,336
  • 4
  • 30
  • 39
  • so when would it be the case of using class factory in swift? almost never? – Swifterino Oct 30 '14 at 15:15
  • Yes, essentially. There might be some edge cases when it might be necessary, but I can't think of any right now. Just use init. – radex Oct 30 '14 at 15:29
  • how about when objects are determined at runtime? Factory and Abstract Factory are a pretty standard OO design patterns. I won't even mention dependency injection and the widely used class cluster pattern. (see http://stackoverflow.com/questions/24014122/custom-class-clusters-in-swift) – Max MacLeod Sep 17 '15 at 11:39
  • 2
    One issue with this is that calling `Person()` tells you nothing about how the object is configured. Let's say I want an initializer which sets a random age for person and therefore doesn't take a parameter. Something like `PersonWithRandomAge` in Objective-C. How would I do this in Swift? – mattsson Apr 18 '16 at 09:39
0

Prior to the recent Xcode 6.1 and Swift 1.1, it was necessary to use factory pattern if construction could fail because init() could not return optionals. This was also why many cocoa/objective-c libraries imported had factory methods.

With the release of Xcode 6.1 and Swift 1.1 and the support for init() that can return optionals, you should use the init() pattern with convenience initializers. With this release, Apple also changed their cocoa/objective-c imports to use the init() -> T? pattern over the factory method.

See https://developer.apple.com/library/ios/releasenotes/DeveloperTools/RN-Xcode/Chapters/xc6_release_notes.html for the release notes.

pkamb
  • 33,281
  • 23
  • 160
  • 191
tng
  • 4,286
  • 5
  • 21
  • 30
  • This is correct, although irrelevant in the context of OP's question where there are no failable initializers. – radex Oct 29 '14 at 20:19
  • What do you mean with "init() that can return optionals"? I thought initializers do not return a value in swift (unlike Objective-C) – Nicolas Miari Jun 30 '15 at 08:42
  • @NicolasMiari It means that "construction may fail". The reason class factories are used in some other languages is because construction cannot fail. With Swift 1.1, Apple introduced "fail-able initializers" (which are written as `init() -> T?`. This effectively means that with Swift you never need factories. – tng Jul 01 '15 at 16:02
  • Oh, missed that one! Thanks for clarifying! – Nicolas Miari Jul 01 '15 at 21:33