When Should I Access Properties With Self in Swift

What is the purpose of self in Swift

self is a reference to the current instance of the class in which the code is running.

In both the init method and the paint method, it allows you to specify that you wish to set the member variable named color using the value passed in the parameter to the method that is also called color.

The paint method cannot reference the parameter passed to init at all (nor vice versa).

So, in your sample code, both methods set the color of the object to some specified value passed in to the method as a parameter.

The init method sets an initial color for the object.

The paint method then allows you to change the color of the object from that initial color.

This might be clearer if the parameters were simply named differently, e.g.:

required init(initialMake: String, initialColor: String) {
self.make = initialMake
self.color = initialColor
}

func paint(newColor: String) {
self.color = newColor
}

In this case, since the functions are member methods, the self is now entirely optional since the compiler knows that color now can only mean the member called color since there is no other variable or parameter with that name, i.e. the paint method could be written simply as:

func paint(newColor: String) {
color = newColor
}

and this would have the exact same behaviour.

However, some people prefer to keep the self prefix for clarity, even where it isn't strictly required since as well as making the intent clear it can help avoid accidental mistakes if variables or member names are changed.

Accessing self from instance properties which are closures

This looks interesting, so I dig little deeper. Found that, you can access the class instance variables within the closure like self.instanceVariable. Then the closure will capture the self within it. So now the self refers to the class instance itself. Your closure should be a lazy property.

A lazy property means that you can refer to self within the default closure, because the lazy property will not be accessed until after initialization has been completed and self is known to exist.

You are missing @lazy so that self is unknown to the closure thats why it is printing it as (Function) my guess.

class TableViewController: UIViewController {
var name = "anil"
// Since swift 2.0 came out @lazy is replaced by lazy
lazy var c1: () -> () = {
println(self)
println(self.name)

}

var c2: () -> () {
get {
return { println(self) }
}
}

var c3: () -> () {
return { println(self) }
}


override func viewDidLoad() {
super.viewDidLoad()
c1()
c2()
c3()
}
}

Output

<_TtC12TableViewApp19TableViewController: 0x10d54e000>

anil

<_TtC12TableViewApp19TableViewController: 0x10d54e000>
<_TtC12TableViewApp19TableViewController: 0x10d54e000>


Update

Assigning closure to a class instance variable results strong reference cycle. You should avoid this. Swift uses Capture list for that

If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles. For more information, see Strong Reference Cycles for Closures.

So the correct usage of closure could be

@lazy  var c1: () -> () = {
[unowned self] in
println(self)
println(self.name)

}

Reference: Swift programming guide

Edit

@lazy has been changed to lazy

What is self used for in Swift?

You will also use self a lot when creating your extensions, example:

extension Int {
func square() -> Int {
return self * self
}

// note: when adding mutating in front of it we don't need to specify the return type
// and instead of "return " whatever
// we have to use "self = " whatever

mutating func squareMe() {
self = self * self
}
}
let x = 3
let y = x.square()
println(x) // 3
printlx(y) // 9

now lets say you want to change the var result itself
you have to use the mutating func to make change itself

var z = 3

println(z) // 3

now lets mutate it

z.squareMe()

println(z) // 9

// now lets see another example using strings :

extension String {
func x(times:Int) -> String {
var result = ""
if times > 0 {
for index in 1...times{
result += self
}
return result
}
return ""
}

// note: when adding mutating in front of it we don't need to specify the return type
// and instead of "return " whatever
// we have to use "self = " whatever

mutating func replicateMe(times:Int){
if times > 1 {
let myString = self
for index in 1...times-1{
self = self + myString
}
} else {
if times != 1 {
self = ""
}
}
}
}


var myString1 = "Abc"
let myString2 = myString1.x(2)

println(myString1) // "Abc"
println(myString2) // "AbcAbc"

now lets change myString1

myString1.replicateMe(3)

println(myString1) // "AbcAbcAbc"

'self' used before all stored properties are initialized in struct

Instead defining your getRandom as an instance method, define it as a static one, then reference it by a type name (CurrentData) or Self

struct CurrentData {
var size: (x: Int, y: Int)
var location: (x: Int, y: Int)

init(size: (x: Int, y: Int)) {
self.size = size
location = (Self.getRandom(size.x), Self.getRandom(size.y))
}

private static func getRandom (_ value:Int) -> Int {
Int.random(in: 0...value-1)
}
}

Other solution is to define your locationproperty as a lazy one, then the self is accessible and the location will be executed only once and after being called in the code.

struct CurrentData {
var size: (x: Int, y: Int)
lazy var location: (x: Int, y: Int) = {
(getRandom(size.x), getRandom(size.y))
}()

init(size: (x: Int, y: Int)) {
self.size = size
}

private func getRandom (_ value:Int) -> Int {
Int.random(in: 0...value-1)
}
}

Is there a tangible benefit to using self outside of closures?

There is.

In the examples you provided it makes no difference, it's purely a style choice. Some people might like it since it explicitly tells you you're modifying self, personally I think it looks cleaner without.

Where it matters is when you have a local variable with the same name. Let's say you have a class that has a var count: Int property. Then, in one of your methods, you declare a new variable with the same name.

The local variable will be used whenever you type count, so if you want to modify or read the object's variable, you'll need to use self.

Some examples where it makes a difference:

guard let count = calculateCount() as? Int else { return }
self.count = count

init(count: Int) {
self.count = count
}

func updateCount(_ count: Int) {
self.count = count
}


Related Topics



Leave a reply



Submit