How Have Multiple Init() with Swift

How have multiple init() with Swift

You cannot have multiple inits without parameters since it would be ambiguous which init method you wanted to use. As an alternative you could either pass the initial values to the init method. Taking the example from your question:

class MyClass {
var myString: String

init(myString: String) {
self.myString = myString
}
}

let a = MyClass(myString: "simple init")

Or, if myString is only supposed to be certain values, you could use an enum:

class MyOtherClass {
enum MyEnum: String {
case Simple = "Simple"
case GoodVar = "GoodVar"
case FooBar = "FooBar"
}

var myString: String

init(arg: MyEnum) {
myString = arg.rawValue
}
}

let b = MyOtherClass(arg: .GoodVar)
println(b.myString) // "GoodVar"

Multiple Initializers in a single class (swift)

Here's how you can add another initializer to the same class that will use two parameters to create an Isosceles triangle:

class Triangle {

var sideA: Int
var sideB: Int
var sideC: Int

init(sideA: Int, sideB: Int, sideC: Int) {

self.sideA = sideA
self.sideB = sideB
self.sideC = sideA
}

init(sideA: Int, sideB: Int) {

self.sideA = sideA
self.sideB = sideB
self.sideC = sideB
}

convenience init(equilateralWithEdge edge:Int) {
self.init(sideA: edge, sideB: edge, sideC:edge)
}

}

Swift Initialization - Why are multiple init functions being called?

super.init() calls self.init(frame:...). Essentially, it's just their way of saying that frame is optional; if you don't pass it, they assign a frame of (0,0,0,0).

func init() {
self.init(frame:CGRectMake(0,0,0,0));
}

how to share a initialize function between two init functions in Swift?

That depends on the stored properties to be initialized.

For example you could assign a default value to the properties

class Foo {

var name = ""
var age = 0

let formatter : DateFormatter = {
let df = DateFormatter()
df.dateFormat = "yyyy/MM/dd"
return df
}()
}

or use implicit unwrapped optionals

class Foo {

var name = String!
var age = Int!

var formatter : DateFormatter!

}

In both cases all properties are initialized and you can first call super and then the initialize method. However the first way is recommended for type safety reasons.

Anyway the rule is:

  • All non-optional properties must be initialized before calling super and self can be only used after calling super

How to implement two inits with same content without code duplication in Swift?

I just had the same problem.

As GoZoner said, marking your variables as optional will work. It's not a very elegant way because you then have to unwrap the value each time you want to access it.

I will file an enhancement request with Apple, maybe we could get something like a "beforeInit" method that is called before every init where we can assign the variables so we don't have to use optional vars.

Until then, I will just put all assignments into a commonInit method which is called from the dedicated initialisers. E.g.:

class GradientView: UIView {
var gradientLayer: CAGradientLayer? // marked as optional, so it does not have to be assigned before super.init

func commonInit() {
gradientLayer = CAGradientLayer()
gradientLayer!.frame = self.bounds
// more setup
}

init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
commonInit()
}

init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}

override func layoutSubviews() {
super.layoutSubviews()
gradientLayer!.frame = self.bounds // unwrap explicitly because the var is marked optional
}
}

Thanks to David I had a look at the book again and I found something which might be helpful for our deduplication efforts without having to use the optional variable hack. One can use a closure to initialize a variable.

Setting a Default Property Value with a Closure or Function

If a stored property’s default value requires some customization or setup, you can use a closure or global function to provide a customized default value for that property. Whenever a new instance of the type that the property belongs to is initialized, the closure or function is called, and its return value is assigned as the property’s default value. These kinds of closures or functions typically create a temporary value of the same type as the property, tailor that value to represent the desired initial state, and then return that temporary value to be used as the property’s default value.

Here’s a skeleton outline of how a closure can be used to provide a default property value:

class SomeClass {
let someProperty: SomeType = {
// create a default value for someProperty inside this closure
// someValue must be of the same type as SomeType
return someValue
}()
}

Note that the closure’s end curly brace is followed by an empty pair of parentheses. This tells Swift to execute the closure immediately. If you omit these parentheses, you are trying to assign the closure itself to the property, and not the return value of the closure.

NOTE

If you use a closure to initialize a property, remember that the rest of the instance has not yet been initialized at the point that the closure is executed. This means that you cannot access any other property values from within your closure, even if those properties have default values. You also cannot use the implicit self property, or call any of the instance’s methods.

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. https://itun.es/de/jEUH0.l

This is the way I will use from now on, because it does not circumvent the useful feature of not allowing nil on variables. For my example it'll look like this:

class GradientView: UIView {
var gradientLayer: CAGradientLayer = {
return CAGradientLayer()
}()

func commonInit() {
gradientLayer.frame = self.bounds
/* more setup */
}

init(coder aDecoder: NSCoder!) {
super.init(coder: aDecoder)
commonInit()
}

init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
}

Swift Pass Multiple Parameters through Init

Create another initializer:

init(title: String?, description: String?) {
self.title = title
self.description = description
}

You may not need to use optionals as parameters, according to your needs...

init(title: String, description: String) {
self.title = title
self.description = description
}

How can I create two initializers for a View in SwiftUI?

You can do it, like this way:

Convenience initializer are accessible in reference types! Not in value types (such as Struct)!



struct CustomView: View {

let title: String
let color: Color

init(title: String, color: Color) {
self.title = title
self.color = color
}

init(title: String) {
self.title = title
self.color = Color.black
}

var body: some View {

Text(title)
.foregroundColor(color)

}

}

use case:

struct ContentView: View {

var body: some View {

CustomView(title: "Hello")

CustomView(title: "Hello", color: Color.red)

}
}

Override multiple overloaded init() methods in Swift

It would seem that your declarations (with override) should be sufficient, however, they seem to need the @objc declarations as well. This works:

class CustomHighlightTextFieldCell : NSTextFieldCell {

required init(coder aCoder: NSCoder!) {
super.init(coder: aCoder)
}

@objc(initImageCell:)
override init(imageCell anImage: NSImage!) {
super.init(imageCell: anImage)
}

@objc(initTextCell:)
override init(textCell aString: String!) {
super.init(textCell: aString)
}
}


Related Topics



Leave a reply



Submit