In a simple example like this, I can omit self for referencing backgroundLayer because it's unambiguous which backgroundLayer the backgroundColor is set on.
class SpecialView: UIView {
let backgroundLayer = CAShapeLayer()
init() {
backgroundLayer.backgroundColor = UIColor.greenColor().CGColor
}
}
But, just like in Objective-C, we can confuse things by adding local variables (or constants) named similarly. Now the backgroundColor is being set on the non-shape layer:
class SpecialView: UIView {
let backgroundLayer = CAShapeLayer()
init() {
var backgroundLayer = CALayer()
backgroundLayer.backgroundColor = UIColor.greenColor().CGColor
}
}
(this is resolved by using self.backgroundLayer.backgroundColor)
In Objective-C I always eschewed ivars for properties and properties were always prefixed with self for clarity. I don't have to worry about ivars in swift but are there other considerations for when I should use self in swift?
The only times self is required are when referencing a property inside a closure and, as you pointed out, to differentiate it from a local variable with the same name.
However, personally, I prefer to always write "self" because:
That is an instant and obvious sign that the variable is a property. This is important because it being a property means that its state can vary more widely and in different ways than a local variable. Also, changing a property has larger implications than changing a local variable.
The code does not need to be updated if you decide to introduce a parameter or variable with the same name as the property
Code can be easily copied in and out of closures that do require self
Most of the time we can skip self. when we access class properties.
However there is one time when we MUST use it: when we try to set self.property in a closure:
dispatch_async(dispatch_get_main_queue(), {
// we cannot assign to properties of self
self.view = nil
// but can access properties
someFunc(view)
})
one time when we SHOULD use it: so you don't mess a local variable with class property:
class MyClass {
var someVar: String = "class prop"
func setProperty(someVar:String = "method attribute") -> () {
print(self.someVar) // Output: class property
print(someVar) // Output: method attribute
}
}
other places where we CAN use self.
before property just to be expressive about were variable/constant comes from.
Looking at Ray Wenderlich's style guide
Use of Self
For conciseness, avoid using self since Swift does not require it to access an object's properties or invoke its methods.
Use self only when required by the compiler (in #escaping closures, or in initializers to disambiguate properties from arguments). In other words, if it compiles without self then omit it.
Swift documentation makes the same recommendation.
The self Property
Every instance of a type has an implicit property called self, which is exactly equivalent to the instance itself. You use the self property to refer to the current instance within its own instance methods.
The increment() method in the example above could have been written like this:
func increment() {
self.count += 1
}
In practice, you don’t need to write self in your code very often. If you don’t explicitly write self, Swift assumes that you are referring to a property or method of the current instance whenever you use a known property or method name within a method. This assumption is demonstrated by the use of count (rather than self.count) inside the three instance methods for Counter.
The main exception to this rule occurs when a parameter name for an instance method has the same name as a property of that instance. In this situation, the parameter name takes precedence, and it becomes necessary to refer to the property in a more qualified way. You use the self property to distinguish between the parameter name and the property name.
Here, self disambiguates between a method parameter called x and an instance property that is also called x:
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.x > x
}
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
print("This point is to the right of the line where x == 1.0")
}
// Prints "This point is to the right of the line where x == 1.0"
I'm going to go against the flow and not use self unless absolutely required.
The reason why is that two of the main reasons to use self is
When capturing self in a block
When setting self as a delegate
In both cases, self will be captured as a strong reference. This might be what you want, but in many cases, you actually want to use a weak one.
Therefor, forcing the developer to use self as an exception and not a rule will make this strong capture more conscious, and let him reflect on this decision.
As Apple documentation says in https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Methods.html
The self Property
Every instance of a type has an implicit property called self, which
is exactly equivalent to the instance itself. You use the self
property to refer to the current instance within its own instance
methods.
The increment() method in the example above could have been written
like this:
func increment() {
self.count += 1
}
In practice, you don’t need to write self in your code very often. If
you don’t explicitly write self, Swift assumes that you are referring
to a property or method of the current instance whenever you use a
known property or method name within a method. This assumption is
demonstrated by the use of count (rather than self.count) inside the
three instance methods for Counter.
The main exception to this rule occurs when a parameter name for an
instance method has the same name as a property of that instance. In
this situation, the parameter name takes precedence, and it becomes
necessary to refer to the property in a more qualified way. You use
the self property to distinguish between the parameter name and the
property name.
Here, self disambiguates between a method parameter called x and an
instance property that is also called x:
struct Point {
var x = 0.0, y = 0.0
func isToTheRightOf(x: Double) -> Bool {
return self.x > x
}
}
let somePoint = Point(x: 4.0, y: 5.0)
if somePoint.isToTheRightOf(x: 1.0) {
print("This point is to the right of the line where x == 1.0")
}
// Prints "This point is to the right of the line where x == 1.0"
Without the self prefix, Swift would assume that both uses of x
referred to the method parameter called x.
I would prefer to keep using self whenever I'm using a property to omit these misunderstandings.
As Nick said, in objective-c we had ivars + synthesized properties which gave the _internal variable names to delineate things. Eg.
#IBOutlet (nonatomic,strong) UITableView *myTableView;
resulting in _myTableView to be (preferably) referenced internally - and self.myTableView to be reference beyond the class. While this is pretty black and white, consider the exception when programmatically instantiating views, you can gain clarity/ simplicity / reduce boilerplate by removing self.
#interface CustomVC:UIViewController
{
UITableView *myTableView;
}
In swift, the public / internal properties clarify this scope.
If it's a public property that other classes will interact with err on self.
Otherwise if it's internal skip self and avoid the automatic repetition.
The compiler will catch you when it's needed.
// UIViewcontroller swift header
public var title: String? // Localized title for use by a parent controller.
public var navigationItem: UINavigationItem { get }
/// In your class
self.title = "Clarity"
self.navigationItem.leftBarButtonItem = UIBarButtonItem()
// In superclass
#property(nonatomic, copy) NSString *screenName // use self.screenName in swift subclass
#IBOutlet myTableView:UITableView // use self
public var myTableView:UITableView // use self
internal var myTableView:UITableView // skip self
var myTableView:UITableView // skip self
Related
I am writing my project and wondered.
When I read literature or watch videos, I see that this is bad practice. Why? Is this bad for the system?
What is the difference between this
class SomeClass {
var someView = SomeView()
var someViewModel = SomeViewModel()
// ...
}
and this
class SomeClass {
var someView: SomeView!
var someViewModel: SomeViewModel?
// ...
}
How to get used to it better?
You have to initialize all instance properties somehow. And you have to do it right up front, either in the declaration line or in your init method.
But what if you don't actually have the initial value until later, like in viewDidLoad? Then it is silly to supply a real heavyweight value only to replace it later:
var v = MyView()
override func viewDidLoad() {
self.v = // get _real_ MyView and assign it in place of that
}
Instead, we use an Optional to mark the fact that we have no value yet; until we obtain and assign one, it will be nil:
var v : MyView? // means it is initially `nil`
override func viewDidLoad() {
self.v = // get _real_ MyView and assign it to our property
}
There's nothing wrong with the first way (which is called a "default property value", by the way), and in fact, often times it's preferable. But of course, the devil is in the details:
How would the initialization of a SomeViewModel work? Without acess the initializer parameters of SomeClass, you're stuck with only being able to construct an instance from a parameter-less init, like SomeViewModel(). What exactly could that do? Suppose it was a person view model, and you had PersonViewModel(). What person? Whats their name? What will this default value do at all?
It's not a great pattern if it requires overwriting the default value with some other value in the initializer
It initializes the value up-front, where sometimes a lazy or computed value might be more appropriate.
Lets say you have a class.
class SomeClass: UIViewController {
private var _dataSource = SomeOtherClass()
init() {
// --> breakpoint
super.init(nibName: nil, bundle: nil)
}
}
At the breakpoint in init - I can see that _dataSource is already allocated. At what point is the class actually getting allocated, and when do the class iVars also get init?
Are there some docs on what happens under the hood?
And what's the difference compared to this?
class SomeClass: UIViewController {
private var _dataSource: SomeOtherClass!
init() {
_dataSource = SomeOtherClass()
super.init(nibName: nil, bundle: nil)
}
}
Thanks,
p.s. Coming from Obj-C to Swift world.
In swift, iVar's are assimilated with properties, so I'll be using the term "property" in the rest of the answer.
Property initialization code runs right before running the code of any initializer, as part of a compiler-genarated "initializer". One method to find out about this is by initializing the property from a function, and set a breakpoint inside that function:
class SomeClass: UIViewController {
private var _dataSource = {
// --> breakpoint
return SomeOtherClass()
}()
init() {
// --> breakpoint
super.init(nibName: nil, bundle: nil)
}
}
You should see a stacktrace like this
BTW, in your second code snippet you don't need to declare the property as implicitly unwrapped, as long as you give it a value either inline or within the initializer the compiler will be happy.
The answer to your second question is that, at runtime, there are no differences between assigning the property the value inline (at the declaration site), or within the initializer. There are other advantages/disadvantages with both approaches, at compile time, like with multiple initializers giving a value inline avoids code duplication.
Swift does not expose allocation or bare iVars. Only init methods and properties are exposed.
Do not make assumptions about how allocation is done or how iVars are initialized. The compiler is free to optimize those details in any way it chooses.
Declaration of properties are straight forward.
class SomeClass: UIViewController {
// This is an instance property. It must be set in init(…) before the call to
// super.init(…).
var _dataSource1: SomeOtherClass
// This is an instance property that is set in its declaration. A way to think
// of this is to imagine it being set after allocation and before init(…) is
// called.
var _dataSource2 = SomeOtherClass()
// This is a lazy property. Instead of being set in init(…), lazy properties
// are set when they are first used.
lazy var _dataSource3 = SomeOtherClass()
// This is a class property accessed with SomeClass._dataSource4. All static
// properties are lazy. So, they are set on first use.
static var _dataSource4 = SomeOtherClass()
}
Initialization in Swift is a two-phase process. In the first phase, each property is assigned an initial value. Whereas in Objective-C this meant assigning zeroes and null values, in Swift it also assigns default property values, like here
class SomeClass: UIViewController {
private var _dataSource = SomeOtherClass()
}
Second phase is when initializers are being called. That is why by the time your breakpoint triggers, the default property value for _dataSource has already been assigned.
The difference between
private var _dataSource = SomeOtherClass()
and
private var _dataSource: SomeOtherClass!
is that in the second example you are only declaring a property, which needs to be initialized somewhere further along the road, whereas in the first one you declare it and provide it with a default value.
Note that in the first example, you don't need to explicitly specify the type of the property, because the compiler can infer it from the default value.
In Swift 3 the dispatch_once function was removed and the migration guide suggests to use initializing closure:
let myGlobal = { … global contains initialization in a call to a closure … }()
_ = myGlobal // using myGlobal will invoke the initialization code only the first time it is used.
I'd like to access 'self' instance variables from within the initializing closure like so:
class SomeClass {
var other = SomeOtherClass()
let initialize: () = {
// self.other - this doesn't work, complains about unresolved identifier 'self'
// how to access self.other here?
} ()
func doSomething() {
// initialize will only be called once
initialize
}
}
Why is 'self' not accessible in the closure and how can make it to be?
This quoted example of the Migration Guide is misleading because it's related to a global variable.
The closure of a instance let constant is called (once) immediately when the class is initialized. That's the reason why it cannot use other variables declared on the same level.
What you can do is to initialize initialize (the variable name is not the best one ;-) ) lazily. The closure is also called only once but – as the guide describes – only the first time (when) it is used.
class SomeClass {
let other = SomeOtherClass()
lazy var initialize : () = {
let test = self.other
test.doSomething()
}()
func doSomething() {
// initialize will only be called once
_ = initialize
}
}
When an instance of the 'SomeClass' class is created, it will first create all of the variables and constants on that instance. During this time, self may not be fully initialised, because it may be halfway through setting up. Because of this, self is not available until after the initialisation step has completed.
In the example, they were talking about a global variable which has no concept of self, or a static constant on the class which also has no concept of self.
If it needs to be an instance method/variable you could:
a) make it a lazy var like
lazy var initialise : ()->Void = {
return {
// can access self here
}
}()
which will be created the first time you call it, rather than during initialisation. Of course you lose the constant that way, and you have to store the closure which is wasteful since you're only executing it once.
b) put the code inside of an init method:
init() {
// if your class doesn't have a super class, you can access self.other here.
// If it does have a super class (like NSObject) you must first call super.init() here to complete the initialisation.
// This can only be done after all other variables have been set.
}
I have a superclass where a vector is being created as a member variable.
class GameScene: SKScene, SKPhysicsContactDelegate {
var floatingBlockPositions: [CGPoint] = [CGPointMake(130.0, 70.0)]
}
I am overriding it in a subclass like so:
class StreetFight: GameScene {
override var floatingBlockPositions: [CGPoint] {
get {
return [CGPointMake(400.0, 70.0), CGPointMake(250.0, 95.0)]
}
set (newValue) {
newValue
}
}
}
I have a class method that mutates it to set another parameter.
temp = 0
for _ in floatingBlockPositions {
floatingBlockPositions[temp].y = floatingBlockPositions[temp].y + positionsForFirstBlock.y + (groundBlockSize.height / 2)
let aerialBlock = SKSpriteNode(imageNamed: "aerialBlock")
aerialBlock.position = floatingBlockPositions[temp]
temp++
}
After debugging, I see that the setter in the subclass is being called, but it is not being set properly because the equals operator in the function is trying to set only one part of one of the CGPoints in the vector, which the setter is not set up to handle, no pun intended. How can I write the setter in the subclass so it recognizes what part of floatingBlockPositions needs to be set and sets it. If possible, should I overload the method, or is there a better way to do it?
You've changed floatingBlockPositions from a stored property to a computed variable (because it has a get). Therefore, you cannot store a new value for it. However, you can create a separate private var and set that, and then in get, if that is set, return that new value.
class HTMLElement {
let name : String
let text: String?
//Declaring a lazy variable that has a strong reference to this closure
lazy var asHTML: Void -> String = {
//Optional binding here
if let text = self.text {
return "<\(self.name)>\(text)<\(self.name)>"
} else {
return "<\(self.name) >"
}
}
init(name: String, text: String? = nil){
self.name = name
self.text = text
}
deinit {
print("\(name) is being deinitialized")
}
}
My Question is: Why is the closure declared Lazy, I know it has something to do with self not being known in the closure, but isn't that the same case for the init method where self hasn't been created?
Secondly,Where exactly is the strong reference cycle in this code example, is it self that strongly references to asHTML, if so where is the second part of the strong referencing that causes the cycle?
Third, Why is the constant text property an optional when constants cannot change value(from nil to a value and back to nil)?
Lastly, What does it mean to have the parameter text: String? = nil in the init method when the init method is used to accept parameters sent by the user?
Sorry for this long question, I'm just confused on the closure strong reference cycle....although I do understand strong reference cycles between class properties and class instances.
1
lazy is used for attributes that are only created when called upon. So before you call myClass.myLazyAttribute it will not take up any space. This also means that it will init after the class has initialised, which can be very useful.
In this case lazy is used to get access to self, like you stated, because self is not available until the instance has been initialised.
2
The apple doc from where code is.
Closures capture the values used in them. In this case it captures self.
It does not create a Strong Reference Cycle between class A and class B, but between itself and a closure. It makes a lot more sense if you imagine that the operation inside the closure takes a very long time. During the execution something else has happened and you want to deinit the instance. But the closure has captured self and it will keep the instance alive until it is done.
By using [unowned self] in you can again deinit the instance while the closure is running. Although this will crash your app.
good info on this specific use : link
In the specific case of a closure, you just need to realize that any variable that is referenced inside of it, gets "owned" by the closure. As long as the closure is around, those objects are guaranteed to be around. The only way to stop that ownership, is to do the [unowned self] or [weak self].
What a Strong Reference Cycle in essence is:
you have an instance of a class
the instance has a reference count higher than 0
there is no longer a reference to the instance available to your program.
Or even shorter: the reference count of the instance is higher than the number of accessible references.
In this case the reference count of self goes up by 1 because it is captured by the closure. We can not access that reference because we can not say something like: closure.selfAttribute, so we can not set that to nil. Only when the closure is finished will the reference count go down by 1 again.
3
It is an optional constant, but it's initial value is set in the init method of the class. So it can receive a value in the init method, but it will be immutable. This is called a late init.
4
This is a function parameter with a default value.
func someFunction(myParamWithDefaultValue : Int = 10) {
print(myParamWithDefaultValue)
}
someFunction() // 10
someFunction(5) // 5