While playing in a Swift playground I noticed that Self, with capital "S", is available along with the lowercase self. Is there any difference between them? If so, what are usages for these two, especially for Self?
Self refers to the type of the current "thing" inside of a protocol (whatever is conforming to the protocol). For an example of its use, see Protocol func returning Self.
The official docs I've found for Self is in Protocol Associated Type Declaration in The Swift Programming Language. It surprisingly is not documented in the sections on protocols or on nested types:
However, now there is a paragraph about Self Type including a code example in the official Swift Programming Language's chapter about Types
Self can also be used in classes, and is useful. Here is an article about it.
Here is an example. You have a class called MyClass. MyClass have methods returning instances of it. Now you add a subclass of MyClass called MySubclass. You want these methods to return instances of MySubclass instead of MyClass. The following code shows how to do it. Note that the methods can be either instance methods or class methods.
class MyClass: CustomStringConvertible {
let text: String
// Use required to ensure subclasses also have this init method
required init(text: String) {
self.text = text
}
class func create() -> Self {
return self.init(text: "Created")
}
func modify() -> Self {
return type(of: self).init(text: "modifid: " + text)
}
var description: String {
return text
}
}
class MySubclass: MyClass {
required init(text: String) {
super.init(text: "MySubclass " + text)
}
}
let myClass = MyClass.create()
let myClassModified = myClass.modify()
let mySubclass = MySubclass.create()
let mySubclassModified = mySubclass.modify()
print(myClass)
print(myClassModified)
print(mySubclass)
print(mySubclassModified)
The following line printed out:
// Created
// modifid: Created
// MySubclass Created
// MySubclass modifid: MySubclass Created
in protocol & Extension declaration use Self else self
extension protocolName where Self: UIView
{
func someFunction()
{
self.layer.shadowColor = UIColor.red.cgColor
}
}
I think this question could use a simpler answer, more focussed on the difference between Self and self, and perhaps aimed at people newer to Swift.
self - explicit reference to the current type or instance of the type in which it occurs.
class MyClass {
func showClass() {
print("\(self)")
}
}
let someClass = MyClass()
someClass.showClass()
// prints "MyClass"
Self - Used specifically in protocol and extension declarations to refer to the eventual type that will conform to the protocol.
protocol MyProtocol {
static func returnSelf() -> Self
}
class MyClass: MyProtocol {
// define class
}
MyClass.returnSelf()
// returns MyClass
The difference is that self is used in types and instances of types to refer to the type that it's in; and Self is used in protocols and extensions where the actual type is not yet known.
In even simpler terms, self is used within an existing type; Self is used to refer to a type that Self is not yet in.
Read more here:
Self - https://docs.swift.org/swift-book/ReferenceManual/Declarations.html#//apple_ref/doc/uid/TP40014097-CH34-XID_543
self - https://docs.swift.org/swift-book/ReferenceManual/Expressions.html
Both -
https://medium.com/the-traveled-ios-developers-guide/swift-keywords-v-3-0-1-f59783bf26c
I understand Self as a type name(class name for example) and self as an instance of a class/struct , for example:
struct Person {
static var documentNumner = "9484930"
var name: String
var computedFullName: String {
return ("\(self.name) with document number: \(Self.documentNumner)")
}
}
You can't use self with a static property but you can use Self
self-refers to the instance or object of a class.
class SampleClassOne {
let name: String
init(name: String) {
self.name = name
}
}
Self-refers to the type of protocol or extension.
class SampleClassTwo {
static let name: String = "Hello"
private func printName() {
print("\(Self.name)")
}
}
protocol SampleProtocol {
func sampleFunc() -> Self
}
Another example to simply understanding together.
extension Int {
var add: Self { //refer to the Type
return self + 100 //refer to the instance
}
}
print(5.add)
Self can also be used as a return type in the protocol extension method body which will return confirming type instance, and for type casting with "as". Please see example below:
extension <Protocol-Name> where Self:<Class-Name> {
static func foo(_ param:Type)-> Self{
guard let abc = method() as? Self else{
return xyz
}
}}
In the nutshell, Self can be used to refer the Type which confirms to the protocol.
Related
In the past we've used Objective-C to anonymously get the sharedInstance of a class this way:
+ (nullable NSObject *)sharedInstanceForClass:(nonnull Class)aClass
{
// sharedPropertyProvider
NSObject<KVASharedPropertyProvider> *sharedPropertyProvider = [aClass conformsToProtocol:#protocol(KVASharedPropertyProvider)]
? (NSObject<KVASharedPropertyProvider> *)aClass
: nil;
if (sharedPropertyProvider == nil)
{
return nil;
}
// return
return [sharedPropertyProvider.class sharedInstance];
}
It's protocol based. We put this protocol on every class we have with a shared instance where we need to do this.
#objc (KVASharedPropertyProvider)
public protocol KVASharedPropertyProvider: AnyObject
{
#objc (sharedInstance)
static var sharedInstance: AnyObject { get }
}
The above works fine in Objective-C (and when called from Swift). When attempting to write the same equivalent code in Swift, however, there appears to be no way to do it. If you take this specific line(s) of Objective-C code:
NSObject<KVASharedPropertyProvider> *sharedPropertyProvider = [aClass conformsToProtocol:#protocol(KVASharedPropertyProvider)]
? (NSObject<KVASharedPropertyProvider> *)aClass
: nil;
And attempt to convert it to what should be this line of Swift:
let sharedPropertyProvider = aClass as? KVASharedPropertyProvider
... initially it appears to succeed. The compiler just warns you that sharedPropertyProvider isn't be used. But as soon as you attempt to use it like so:
let sharedInstance = sharedPropertyProvider?.sharedInstance
It gives you the compiler warning back on the previous line where you did the cast:
Cast from 'AnyClass' (aka 'AnyObject.Type') to unrelated type
'KVASharedPropertyProvider' always fails
Any ideas? Is Swift simply not capable of casting AnyClass to a protocol in the same way that it could be in Objective-C?
In case you're wondering why we need to do this, it's because we have multiple xcframeworks that need to operate independently, and one xcframework (a core module) needs to optionally get the shared instance of a higher level framework to provide special processing if present (i.e. if installed) but that processing must be initiated from the lower level.
Edit:
It was asked what this code looked like in Swift (which does not work). It looks like this:
static func shared(forClass aClass: AnyClass) -> AnyObject?
{
guard let sharedPropertyProvider = aClass as? KVASharedPropertyProvider else
{
return nil
}
return type(of: sharedPropertyProvider).sharedInstance
}
The above generates the warning:
Cast from 'AnyClass' (aka 'AnyObject.Type') to unrelated type
'KVASharedPropertyProvider' always fails
It was suggested I may need to use KVASharedPropertyProvider.Protocol. That looks like this:
static func shared(forClass aClass: AnyClass) -> AnyObject?
{
guard let sharedPropertyProvider = aClass as? KVASharedPropertyProvider.Protocol else
{
return nil
}
return type(of: sharedPropertyProvider).sharedInstance
}
And that generates the warning:
Cast from 'AnyClass' (aka 'AnyObject.Type') to unrelated type
'KVASharedPropertyProvider.Protocol' always fails
So, I assume you have something like this
protocol SharedProvider {
static var shared: AnyObject { get }
}
class MySharedProvider: SharedProvider {
static var shared: AnyObject = MySharedProvider()
}
If you want to use AnyObject/AnyClass
func sharedInstanceForClass(_ aClass: AnyClass) -> AnyObject? {
return (aClass as? SharedProvider.Type)?.shared
}
Better approach
func sharedInstanceForClass<T: SharedProvider>(_ aClass: T.Type) -> AnyObject {
return T.shared
}
I'm trying to create a static method on a generic class which takes in a closure as parameter and creates an instance of the class and passes it the closure. The catch is that I want to subclass this and ensure that the closure conforms to any subclass I use.
I know that you can use "Self" as a return type for a static method, but when I try to use it in the method header, I get the following error:
"'Self' is only available in a protocol or as the result of a method
in a class"
I'd like to do something like this:
class GenericClass: NSObject {
required override init() {
super.init()
}
static func createAndExecuteAsync(block: (Self) -> Void) {
DispatchQueue.global().async {
let instance = self.init()
block(instance)
}
}
}
class OtherClass: GenericClass {
// ...
}
Somewhere else...
OtherClass.createAndExecuteAsync { (instance: OtherClass) in
// Do stuff to instance
}
UPDATE:
Thanks to Hamish's solution in this post, I'm closer to a solution. I can use Self in the desired way if I first create a protocol for my generic class. However that forces me to make OtherClass final, which isn't desirable for my situation.
Without making OtherClass final, I get the following error:
Protocol 'GenericClass' requirement 'createAndExecuteAsync(block:)'
cannot be satisfied by a non-final class ('OtherClass') because it
uses 'Self' in a non-parameter, non-result type position.
Here's what it would look like:
protocol GenericClass {
init()
static func createAndExecuteAsync(block: #escaping (Self) -> Void)
}
extension GenericClass {
static func createAndExecuteAsync(block: #escaping (Self) -> Void) {
DispatchQueue.global().async {
let instance = self.init()
block(instance)
}
}
}
final class OtherClass : GenericClass {
var myProperty = 1
required init() { }
}
// Somewhere else...
OtherClass.createAndExecuteAsync { (instance) in
instance.myProperty = 2
}
Perhaps you could use a global generic function with a slightly different usage syntax.
for example:
func createAndExecuteAsync<T:GenericClass>(_ objectType:T.Type, _ block:#escaping (T) -> Void)
{
DispatchQueue.global().async
{
let instance = T.init()
block(instance)
}
}
createAndExecuteAsync(OtherClass.self){ $0.myProperty = 2 }
// instead of OtherClass.createAndExecuteAsync{ $0.myProperty = 2 }
If I have the following code:
class MyClass {
...
}
protocol MyProtocol {
...
}
Is it possible to declare a type that accepts a class or subclass of MyClass conforming to MyProtocol?
e.g. in pseudo code:
var thing: MyClass & MyProtocol = ...
The naive approach works (i.e. specify the type first and then use it in the variable declaration):
class MCImplementingMP: MyClass, MyProtocol {
}
var thing: MCImplementingMP = ...
Nope, it was possible in Objective-C but not possible in Swift.
All solutions that I know looks like hacks and require lot of runtime type checking. So I came out with my own - declare a wrapper type which can act like needed class or protocol depending on circumstances:
class MyClass {}
protocol MyProtocol: class {}
class Wrapper {
var instance: AnyObject
init?(instance: MyClass) {
guard instance is MyProtocol else { return nil }
self.instance = instance
}
init?(instance: MyProtocol) {
guard instance is MyClass else { return nil }
self.instance = instance
}
var instanceAsMyClass: MyClass {
return instance as! MyClass
}
var instanceAsMyProtocol: MyProtocol {
return instance as! MyProtocol
}
}
You may want to change property names but idea is clear.
I want to implement something like "registerClassForAction".
For that purpose, I have defined a protocol:
#objc protocol TestProt {
func testMe() -> String
}
Let's do a class declaration:
class TestClass: NSObject, TestProt {
func testMe() -> String {
return "test"
}
}
I define the function to register the object in another class:
func registerClassForAction(aClass: AnyClass) { ... }
Switching to the REPL, I'd simulate the register method:
let aClass: AnyClass = TestClass.classForCoder() //or .self
let tClass = aClass as NSObject.Type
let tInst = tClass() as TestProt
tInst.testMe()
This currently works but is there another way to instantiate tClass, other than with
let tClass = aClass as NSObject.Type
Reason for asking, I'd like to explore the chance of getting rid of the NSObject so my TestClass does not to inherit from NSObject. Delegation was considered, but I'd like to control the lifetime of tInst and be able to dealloc it at a specific point in time.
thanks for helping
Ron
This is possible in Swift 2.0 without requiring #objc or subclassing NSObject:
protocol TestProt {
func testMe() -> String
}
class TestClass: TestProt {
// This init is required in order
// to construct an instance with
// a metatype value (class.init())
required init() {
}
func testMe() -> String {
return "Hello from TestClass"
}
}
let theClass = TestClass.self
let tInst: TestProt = theClass.init()
tInst.testMe()
I have a simple Result object which should contain an object (class, struct or enum) and a Bool to say whether it was cancelled or not. I need to interrogate this object along its path (before it gets to its destination, where the destination knows what kind of object to expect) to determine whether it was cancelled or not (without worrying about the accompanying object at that moment). My object looks like:
import Foundation
#objc protocol Resultable {
var didCancel: Bool { get }
}
class Result<T>: Resultable {
let didCancel: Bool
let object: T?
init(didCancel: Bool, object: T?) {
self.didCancel = didCancel
self.object = object
}
}
The idea being that my Result object can wrap the didCancel flag and the actual object (which can be of any type), and the fact that it implements the Resultable protocol means that I can interrogate it at any point to see whether it was cancelled by casting it to Resultable.
I understand (while not liking it) that the protocol has to be prefixed with #objc so that we can cast to it (according to the Apple docs). Unfortunately, when I run the code below (in a playground or in a project), I get a nasty "does not implement methodSignatureForSelector:" error message:
let test = Result(didCancel: false, object: NSArray())
println(test.didCancel)
// transform the object into the form it will be received in
let anyTest: AnyObject = test
if let castTest = anyTest as? Resultable {
println(castTest.didCancel)
}
It seems that despite the protocol being prefixed with #objc, it also wants the actual class to inherit from NSObject (and this is not a requirement that Apple makes explicit). This is obviously a problem for a generic class.
Is there anything I am missing here? Any way to get this to work? Failing that, are there any workarounds (although I strongly believe that this kind of thing should be possible - perhaps we can hope that Apple will do away with the #objc protocol casting requirement at some stage)?
UPDATE
It looks like this is solved with Swift 1.2
You can now cast to a non-ObjC protocol, and without the object having to inherit from NSObject.
It seems that despite the protocol being prefixed with #objc, it also wants the actual class to inherit from NSObject
This is not true. For example, the following code works as expected:
#objc protocol MyProtocol {
var flag: Bool { get }
}
class MyClass: MyProtocol {
let flag = true
}
let foo:AnyObject = MyClass()
if let p = foo as? MyProtocol {
println(p.flag)
}
The problems is that: Any methods/properties declared in Swift Generic classes are invisible from Objective-C. Hence, from the perspective of #objc protocol Resultable, didCancel property declared in Result<T> is invisible. That's why methodSignatureForSelector: is called.
The workaround here is very annoying: You have to have non Generic base class for Result that implements didCancel.
#objc protocol Resultable {
var didCancel: Bool { get }
}
class ResultBase: Resultable {
let didCancel: Bool
init(didCancel: Bool) { self.didCancel = didCancel }
}
class Result<T>: ResultBase, Resultable {
// ^^^^^^^^^^^^
// You have to explicitly conforms `Resultable` here as well for some reason :/
let object: T?
init(didCancel: Bool, object: T?) {
self.object = object
super.init(didCancel: didCancel)
}
}
let test = Result(didCancel: false, object: NSArray())
let anyTest: AnyObject = test
if let castTest = anyTest as? Resultable {
println(castTest.didCancel) // -> outputs "false"
}