a tale of two `self`
A while ago, I came across a problematic piece of code that turned out to be an interesting one:
extension UIViewController {
static var screenName = String(describing: self)
}
The value of screenName is always equal to (Function)
. But what I needed was the type of UIViewController
instance as a String.
For example:
class ReaderViewController: UIViewController { ... }
print(ReaderViewController)
// Expected Output: ReaderViewController
// Actual Output: (Function)
But why is that so?
I tried to simplify the problematic piece of code and reduce the variables that were involved. In the first step, I took out screenName
from the extension and put it inside a class:
class ReaderViewController: UIViewController {
static var screenName = String(describing: self)
}
The result was the same.
What if ReaderViewController
doesn’t inherit from UIViewController
?
class ReaderViewController {
static var screenName = String(describing: self)
}
Boom! Compiler Error:
Use of unresolved identifier 'self'.
By trial and error I managed to narrow down the problem to the point that led me to this conclusion:
- If the root class of
ReaderViewController
isNSObject
, the value ofscreenName
is(Function)
. - Otherwise, we get the compiler error
It looks like we have two different problems here that need to be investigated separately. But actually, when I was looking for the root cause of the former one, I found an explanation for the later one too.
When I jumped to the definition of NSObject
, I faced this (summarized) code:
public protocol NSObjectProtocol {
//...
func `self`() -> Self
//...
}
@available(iOS 2.0, *)
open class NSObject : NSObjectProtocol {
//...
}
self
is a method that returns the object which it is called on.
It explains why String(describing: self)
returns (Function)
within a subclass of NSObject
. But it doesn’t explain why within the initializer expression of a stored type property, self
isn’t available.
I replaced the stored type property with a computed one, and it silenced the compiler-error problem:
class ReaderViewController {
static var screenName: String {
return String(describing: self)
}
}
Still, I don’t know why referring to self within type property initializer expression caused that compiler error and I have asked it here.
By the way, at least now I know that self within type property initializer expression is not available, so it is an unresolved identifier. If the class is a subclass of NSObject
, in the absence of self, NSObject
’s self
( which is a method ) is available and String(describing: self) returns the type of it which is (Function)
.
P.S. While I was writing this post, I found this related question on Swift Forum:
Do you have question, suggestion, feedback? Hit me on twitter: @coybit🙂