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 location
property 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
Nsurlsession Concurrent Requests With Alamofire
How to Round a Double to the Nearest Int in Swift
How to Set Layer Cornerradius For Only Bottom-Left, Bottom-Right, and Top-Left Corner
How to Get the Name of Enumeration Value in Swift
Iterate Over Collection Two At a Time in Swift
Updating the Ui Using Dispatch_Async in Swift
Noop For Swift'S Exhaustive Switch Statements
What Is the Point of Having Two Different Names For the Same Parameter
Saving Picked Image to Coredata
Custom Back Button For Navigationview'S Navigation Bar in Swiftui
Prevent Dismissal of Uialertcontroller
Can Swift Convert a Class/Struct Data into Dictionary
How to Display My App Documents in the Files App For Iphone