Swift nil check performance - ios

I have a computed property that does a nil check.
var _textSize: CGSize?
var textSize: CGSize {
get {
if _textSize == nil {
// compute _textSize
}
return _textSize
}
}
When profiling in Instruments, the == nil check appears as:
I believe that the static == infix<A where ...> (A?, A?) -> Bool is the nil check. Is this the case and if so are nil checks expensive?

The correct answer really depends by what you mean with "expensive".
My point of view
However, IMHO, checking if a value is nil is not an expensive operation.
It is executed in time O(1), so it's a constant time and does not grow depending on other values.
Finally it's a very easy operation for the CPU.
Class vs Struct
I suppose there is a difference (in terms of required time) if the computed property does belong to a Class or to a Struct.
Class
In the first case (Class) the OS needs to retrieve from the Heap the instance of the class and next checking whether the property is nil. The Heap is on the RAM which is fast (but not the fastest memory on the device).
Struct
On the other hand, if we are using a Struct, data about the computed property is available on the Stack which if faster then the Heap.
Wrap up
So, in conclusion:
checking whether the computed property of a Class is nil is fast
checking whether the computed property of a Struct is nil is very fast

Related

How to use lazy initialization with getter/setter method?

How i can use lazy initialization with get and set() closure.
Here is lazy initialization code:
lazy var pi: Double = {
// Calculations...
return resultOfCalculation
}()
and here is getter/setter code :
var pi: Double {
get {
//code to execute
return someValue
}
set(newValue) {
//code to execute
}
}
I assume what you're trying to do is lazily generate the default for a writable property. I often find that people jump to laziness when it isn't needed. Make sure this is really worth the trouble. This would only be worth it if the default value is rarely used, but fairly expensive to create. But if that's your situation, this is one way to do it.
lazy implements one very specific and fairly limited pattern that often is not what you want. (It's not clear at all that lazy was a valuable addition to the language given how it works, and there is active work in replacing it with a much more powerful and useful system of attributes.) When lazy isn't the tool you want, you just build your own. In your example, it would look like this:
private var _pi: Double?
var pi: Double {
get {
if let pi = _pi { return pi }
let result = // calculations....
_pi = result
return result
}
set { _pi = newValue }
}
This said, in most of the cases I've seen this come up, it's better to use a default value in init:
func computePi() -> Double {
// compute and return value
}
// This is global. Globals are lazy (in a thread-safe way) automatically.
let computedPi = computePi()
struct X {
let pi: Double // I'm assuming it was var only because it might be overridden
init(pi: Double = computedPi) {
self.pi = pi
}
}
Doing it this way only computes pi once in the whole program (rather than once per instance). And it lets us make pi "write-exactly-once" rather than mutable state. (That may or may not match your needs; if it really needs to be writable, then var.)
A similar default value approach can be used for objects that are expensive to construct (rather than static things that are expensive to compute) without needing a global.
struct X {
let pi: Double
init(pi: ExpensiveObject = ExpensiveObject()) {
self.pi = pi
}
}
But sometimes getters and setters are a better fit.
The point of a lazy variable is that it is not initialized until it is fetched, thus preventing its (possibly expensive) initializer from running until and unless the value of the variable is accessed.
Well, that's exactly what a getter for a calculated variable does too! It doesn't run until and unless it is called. Therefore, a getter for a calculated variable is lazy.
The question, on the whole, is thus meaningless. (The phrase "How i can use lazy initialization" reveals the flaw, since a calculated variable is never initialized — it is calculated!)

ObjectIdentifier needed for Swift equality?

We have multiple instances of a custom Swift class, which inherits from SKSpriteNode, and were able to execute the following code (grossly simplified for this question) correctly:
let instance1 = CustomClass()
let instance2 = CustomClass()
let instance3 = CustomClass()
let instance4 = CustomClass()
let array1 = [instance1, instance2]
let array2 = [instance3, instance4]
func check(testInstance: CustomClass) -> Bool {
return array1.filter({ $0 == testInstance }).count > 0
}
check(testInstance: instance3)
In other words, executing check(testInstance: instance3) returned false as expected.
However, we made a bunch of changes, and check stopped working.
CustomClass does not implement the Equatable protocol. We just want to detect unique instances.
It only started working when we used ObjectIdentifier, meaning the function changed to this:
func check(testInstance: CustomClass) -> Bool {
return array1.filter({ ObjectIdentifier($0) == ObjectIdentifier(testInstance) }).count > 0
}
Why is ObjectIdentifier needed, and when should it be used for object equality?
This was written with Swift 3.
Why is ObjectIdentifier needed, and when should it be used for object equality?
You don't need to use ObjectIdentifier in order to perform an identity comparison in this case, you can simply use the identity operator === instead which, as Martin says here, for class instances is equivalent to using ObjectIdentifier's == overload:
func check(testInstance: CustomClass) -> Bool {
return array1.contains(where: { $0 === testInstance })
}
Also note we're using contains(where:) over filter{...}.count > 0, as the former will short-circuit upon finding a matching element, whereas the latter evaluates the entire sequence (and creates an unnecessary intermediate array).
The direct use of == to perform an identity comparison of objects may have worked due to the fact that CustomClass ultimately inherits from NSObject, which conforms to Equatable by defining an == overload that calls isEqual(_:), which by default performs an identity comparison.
However in general, this should not be relied upon – the implementation of isEqual(_:) can be overridden to perform a comparison based on property values rather than identity. Furthermore, semantically Equatable requires that the implementation of == is based all on visible aspects (i.e property values) of the instances being compared.
From the documentation:
Equality implies substitutability — any two instances that compare
equally can be used interchangeably in any code that depends on their
values. To maintain substitutability, the == operator should take into
account all visible aspects of an Equatable type.
Therefore using == for an identity comparison on your class was never correct, even though it may have worked initially.
As for when ObjectIdentifier should be used, really you should never need it just to perform an identity comparison. For classes, you should use the === operator, and for metatypes, you should simply use the == overload defined specifically for them (as in that case, identity just happens to equality, as each new metatype instance is unique).
The main use of ObjectIdentifier is really its hashValue implementation, which is derived from the pointer value of the thing that it's initialised with. This can be useful, for example, in allowing metatypes to be Dictionary keys (compare Make a Swift dictionary where the key is "Type"?).

initializing class properties before use in Swift/iOS

I'm having trouble grasping the proper way of instantiating variables that always need to be set before an object is fully functional but may need to be instantiated after the constructor. Based on Swift's other conventions and restrictions it seems like there is a design pattern I'm unaware of.
Here is my use case:
I have a class that inherits from UIViewController and will programmatically create views based on user actions
I need to attach these views to this class, but to do so I need to retrieve their content based on configuration data supplied by another controller
I don't care if this configuration data is passed to the constructor (in which case it would always be required) or supplied by a secondary call to this object before it is used
My problem seems to be that both of the approaches in bullet 3 seem flawed.
In the first case, there is only one legitimate constructor this class can be called with, yet I'm forced to override other constructors and initialize member variables with fake values even if the other constructors are never intended to be used (I'm also trying to keep these variables as let types based on Swift's best practices).
In the second case, I'm effectively splitting my constructor into two parts and introduce an additional point of failure in case the second part fails to be called prior to class being used. I also can't move this second part to a method that's guaranteed to be called prior to usage (such as viewDidLoad) because I still need to pass in additional arguments from the config. While I can make sure to call the initPartTwo manually, I'd prefer to have a mechanism that better groups it with the actual constructor. I can't be the first one to run into this and it seems like there is a pattern I'm not seeing to make this cleaner.
UPDATE:
I ended up going with a modified version of the pattern matt suggested:
struct Thing {
let item1: String
let item2: String
struct Config {
let item3: String
let item4: String
}
var config:Config! {
willSet {
if self.config != nil {
fatalError("tried to initialize config twice")
}
}
}
init() {
self.item1 = ...
self.item2 = ...
...
}
public func phaseTwoInit(item3: String, item4: String) {
self.item3 = item3
self.item4 = item4
...
}
}
var t = Thing()
...
t.phaseTwoInit(...)
...
// start using t
If an initial instance variable property value can't be supplied at object initialization time, the usual thing is to declare it as an Optional. That way it doesn't need to be initialized by the class's initializers (it has a value - it is nil automatically), plus your code subsequently can distinguished uninitialized (nil) from initialized (not nil).
If the Optional if an implicitly unwrapped Optional, this arrangement need have no particular effect on your code (i.e. it won't have to be peppered with unwrappings).
If your objection is that you are forced to open the door to multiple settings of this instance variable because now it must be declared with var, then close the door with a setter observer:
struct Thing {
var name:String! {
willSet {
if self.name != nil {
fatalError("tried to set name twice")
}
}
}
}
var t = Thing()
t.name = "Matt" // no problem
t.name = "Rumplestiltskin" // crash

Faulting or "lazy initialisation" pattern in Swift

I commonly use a "faulting" or lazy initialization pattern in iOS when dealing with big objects.
Whenever a class has a property pointing to a "fat" object, I create a custom getter that checks if the iVar is nil. If it is, it creates the fat object and returns it. If it isn't, it just returns the "fat" object.
The container of this property also subscribes to memory warnings, and when one is received, it sets the iVar to nil, reducing the memory footprint. As you see, it's pretty similar to faulting in Core Data.
I'm trying to reproduce this in Swift, but haven't found a decent and elegant solution so far.
a) First Attempt: lazy stored properties
This doesn't work, because if I set the property to nil, it will remain nil forever. The "magic" only happens the first time you access the property:
struct FatThing{
// I represent something big, which might have to be
// "faulted" (set to nil) when a memory warning
// is received
var bigThing = "I'm fat"
}
class Container {
lazy var fat: FatThing? = FatThing()
}
var c = Container()
c.fat
c.fat = nil
c.fat // returns nil
b) Second attempt: A stored property with observers
This also fails, because of the lack of get observers. I need a willGet and didGet, not just willSet and didSet.
Why on Earth are there no get obeservers? What's the use of this half backed thing called observers?
c) Third attempt: A computed property with a stored helper property
This is the only working option I've found so far, but it's as ugly as a baboon's rear end!
struct FatThing{
// I represent something big, which might have to be
// "faulted" (set to nil) when a memory warning
// is received
var bigThing = "I'm fat"
}
class Container {
private var _fat : FatThing? // having this extra and exposed var kills my inner child
var fat: FatThing? {
get{
if _fat == nil {
_fat = FatThing()
}
return _fat
}
set{
_fat = newValue
}
}
}
var c = Container()
c.fat
c.fat = nil
c.fat // returns FatThing
So much for making my code look simpler and shorter...
Is there a simple and elegant way to implement this? This is no exotic stuff in a memory deprived environment as iOS!
The ability to override the getter or setter individually is a peculiarity of objective C that has no counterpart in swift.
The right option at your disposal is no. 3, using a backing property to store the fat data and a computed property to make it accessible. I agree that there's some boilerplate code, but that's the tradeoff for having what you need.
However, if you use that pattern frequently, then you can create a protocol:
protocol Instantiable {
init()
}
and implement it in your FatThing struct/class. Next, create a generic function containing the boilerplate code:
func lazyInitializer<T: Instantiable>(inout property: T?) -> T {
if property == nil {
property = T()
}
return property!
}
Note that T must implement Instantiable - that allows you to create an instance with a parameterless constructor.
Last, use it as follows:
private var _fat : FatThing? // having this extra and exposed var kills my inner child
var fat: FatThing? {
get { return lazyInitializer(&self._fat) }
set { _fat = newValue }
}
Note that in your code you don't have to declare the fat computer property as optional - you are ensuring in the get implementation that it is always not nil, so a better implementation is:
var fat: FatThing {
get{
if _fat == nil {
_fat = FatThing()
}
return _fat!
}
set{
_fat = newValue
}
}

Swift vs ObjC initialisation process?

In ObjectiveC we create objects like
-(instancetype)init()
{
return [super init]; // Here it returns initialised value
}
Class *obj = [[Class alloc]init]
But swift initialiser wont return any value.
From Swift docs
Unlike Objective-C initializers, Swift initializers do not return a value. Their primary role is to ensure that new instances of a type are correctly initialized before they are used for the first time.
init()
{
super.init()
}
let obj = Class()
Now how swift initialiser returns the instance to variable obj?.
How the allocation and initialisation occurs in swift?
As #NikolayKasyanov says, with the init family of initialisers, the return (of self) is implicit, and you can't return nil. However, if you want to initialise an optional that could return nil, use a class function. EG:
class NumberLessThan5: Int {
var myNumber: Int
init (i: Int) {
self.myNumber = i
}
class func createWithInt(i: Int) -> NumberLessThan5? {
if i < 5 {
return NumberLessThan5(i)
} else {
return nil
}
}
}
It's just a convention. Swift initialiser sets up a valid instance and could not theoretically return anything other that a valid instance, so there's no point in explicit return.
So (from my point of view) allocation & initialisation sequence looks like this:
Runtime allocates instance of requested class
Initializer is called with self set to allocated instance
Initializer performs setup
Runtime returns initialised instance to client code
Although this approach breaks some useful Objective-C patterns like initialisers returning nil on error, the guarantee that instantiation always succeeds allows compiler to perform some optimisations. Also without dropping initialisers returning nil it would be impossible to actually remove nil from language, it would seem weird if initialisers were returning optionals.
Initialisers DO NOT return any value explicitly because it's not called directly by the code(actually it returns a value which is opaque to user ).
Initialisers are invoked by memory allocation and object initialization code in the runtime, on creating a new instance for a particular type (type- struct or class).Runtime uses variable's type data generated by the compiler to determine how much space is required to store an object instance in memory.
After this space is allocated, the initialiser is called as an internal part of initialisation process to initialise the contents of the fields. Then, when the initialiser exits, the runtime returns the newly-created instance.

Resources