Variable of type Self in static context - swift

I have to modify an existing static method with return type Self.
I am using Self as it is required to work for subclasses of A as well. As the modification potentially needs a dispatch sync block to create the data for the returnee, I have to introduce a local variable of type Self.
Error:
'Self' is only available in a protocol or as the result of a method in a class;
class A {
//...
}
class B:A {
//...
}
extension A {
static private func foo() -> Self {
var myVar: Self? //Error: 'Self' is only available in a protocol or as the result of a method in a class;
// Get data for myVar, potentially in a dispatch sync block on another queue
guard let safeVar = myVar else {
return someGarbagr
}
return myVar
}
}
Intended usage:
func someFunctionSomewhere() {
let instanceOfB = B.foo()
// use instanceOfB
}
I have tried all I can think of already:
type(of:Self)
Self.Type
...
I would like to avoid modifying it to a generic method for several reasons. The main reason is that we would have to mention the type explicitly to make a generic version be able to refer the return type:
let instanceOfB: B = B.foo()

Related

Why is declaring self not required in structures where it's required in classes?

Why is declaring self not required in structures where it's required in classes? I don't know if there are other examples where this is the case but with escaping closures, it is. If the closure is non-optional (and thus non-escaping), there is no requirement to declare self in either of the two.
class SomeClass {
let someProperty = 1
func someMethod(completion: (() -> Void)?) {}
func anotherMethod() {
someMethod {
print(self.someProperty) // declaring self is required
}
}
}
struct SomeStruct {
let someProperty = 1
func someMethod(completion: (() -> Void)?) {}
func anotherMethod() {
someMethod {
print(someProperty) // declaring self is not required
}
}
}
The purpose of including self when using properties inside an escaping closure (whether optional closure or one explicitly marked as #escaping) with reference types is to make the capture semantics explicit. As the compiler warns us if we remove self reference:
Reference to property 'someProperty' in closure requires explicit use of 'self' to make capture semantics explicit.
But there are no ambiguous capture semantics with structs. You are always dealing with a copy inside the escaping closure. It is only ambiguous with reference types, where you need self to make clear where the strong reference cycle might be introduced, which instance you are referencing, etc.
By the way, with class types, referencing self in conjunction with the property is not the only way to make the capture semantics explicit. For example, you can make your intent explicit with a “capture list”, either:
Capture the property only:
class SomeClass {
var someProperty = 1
func someMethod(completion: #escaping () -> Void) { ... }
func anotherMethod() {
someMethod { [someProperty] in // this captures the property, but not `self`
print(someProperty)
}
}
}
Or capture self:
class SomeClass {
var someProperty = 1
func someMethod(completion: #escaping () -> Void) { ... }
func anotherMethod() {
someMethod { [self] in // this explicitly captures `self`
print(someProperty)
}
}
}
Both of these approaches also make it explicit what you are capturing.
For classes, closures provide a mechanism to increment a reference count, thus "keeping the object alive".
Maybe you're okay with just capturing someProperty. Maybe not! The compiler doesn't know if you're using a closure in order to increment the reference, so it makes you be explicit about your intentions.
Not only is that a non-issue with structs, but so is the possibility of mutation, which is strictly disallowed.
Let's say you wanted anotherMethod to allow mutation of any kind, in a struct. You could start by marking it as mutating…
struct SomeStruct {
func someMethod(completion: (() -> Void)?) {}
mutating func anotherMethod() {
someMethod {
self
}
}
}
…but no, that's an error:
Escaping closure captures mutating 'self' parameter
Capture self, though…
mutating func anotherMethod() {
someMethod { [self] in
self
}
}
…and that's fine.
And it's also the only option Swift allows. When you use an escaping closure from within a struct, you can only use an immutable capture of an instance. i.e. [self] in is implicit, for nonmutating methods.
This can yield unexpected results. Be careful.
struct SomeStruct {
var someProperty = 1
func anotherMethod() {
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
print(someProperty)
}
}
}
var s = SomeStruct()
s.anotherMethod() // 1, even though it's printed after the following reassignment
s.someProperty = 2
s.anotherMethod() // 2
I think it helps to think about what method syntax is shorthand for.
s.anotherMethod()
is really
SomeStruct.anotherMethod(s)()
You can visualize the immutability there, because there's no &.

swift convenience init and generic class

I have a problem creating a convenience init method that then calls a designated init on a class with generic type parameters. Here is the swift 3.1 XCode Version 8.3.2 (8E2002) playground
protocol A {
var items: [String] { get set }
func doSomething()
}
struct Section : A {
var items: [String] = []
func doSomething() {
print("doSomething")
items.forEach { print($0) }
}
}
class DataSource<T: A> {
var sections: [T]
init(sections: [T]) {
self.sections = sections
}
func process() {
sections.forEach { $0.doSomething() }
}
convenience init() {
var section = Section()
section.items.append("Goodbye")
section.items.append("Swift")
self.init(sections: [section])
}
}
/*: Client */
var section = Section()
section.items.append("Hello")
section.items.append("Swift")
let ds = DataSource(sections: [section])
ds.process()
If no convenience init exists, then the code beneath the /*: Client */ section compiles and executes without issue. If I add in the convenience init I get the following compilation error:
cannot convert value of type '[Section]' to expected argument type '[_]'
self.init(sections: [section])
I wouldn't think that this would be an issue since in the convenience init I am creating a Section struct which implements the protocol A which satisfies the generic constraint on the DataSource class. The convenience init is performing the same operations as the client code, yet it is unable to convert a [Section] into a [A]. Is this an initialization sequencing issue?
Generic placeholders are satisfied at the usage of the given generic type – therefore inside your convenience init, you cannot assume that T is a Section. It's an arbitrary concrete type that conforms to A.
For example, it would be perfectly legal for the caller to define a
struct SomeOtherSection : A {...}
and then call your convenience initialiser with T being SomeOtherSection.
The solution in this case is simple, you can just add your convenience initialiser in an extension of DataSource, where T is constrained to being Section – therefore allowing you to call init(sections:) with a [Section]:
extension DataSource where T == Section {
convenience init() {
var section = Section()
section.items.append("Goodbye")
section.items.append("Swift")
self.init(sections: [section])
}
}
// ...
// compiler will infer that T == Section here.
let ds = DataSource()

Cannot convert return expression of type 'child' to return type T

I am struggling a bit with generics in Swift.
I have the following code:
class Parent {
init(value: SomeThing) {
// ...
}
func clone<T: Parent>() -> T {
return T(value: SomeThing)
}
}
class Child : Parent {
var otherValue: SomeThingElse?
override func clone<T>() -> T where T : Parent {
let clone: Child = super.clone()
clone.otherValue = self.otherValue
return clone //ERROR: cannot convert return expression of type 'Child' to return type T
}
}
The idea is to create a simple method that returns a new copy of a child instance with identical values.
I don't want to write the constructor out for each Child classtype. (it has a lot of params in the real classes, and I like to keep it clean).
The error I get is:
cannot convert return expression of type 'Child' to return type T
Suggested solution is to make it return clone as! T. But that way I lose the reason to use a generic class.
Any idea how to solve this while keeping it generic and not write out the constructor in each class?
You need to have a return type of Self, rather than using a generic placeholder constrained to Parent. With the generic placeholder, you're saying that clone() can return an instance of any specific concrete type that inherits from Parent. However that's not true – you only want to return instances of the same type as the receiver, which is what Self expresses.
You'll then also need to implement a required initialiser so that it's available to call on all subclasses, allowing clone() to be called on them without them necessarily overriding it.
struct Something {}
struct SomethingElse {}
class Parent {
var something: Something
required init(something: Something) {
self.something = something
}
func clone() -> Self {
// call the initialiser on the dynamic metatype of the instance,
// ensuring that we're instantiating a Self instance.
return type(of: self).init(something: something)
}
}
The implementation of Child then should be as simple as:
class Child : Parent {
var somethingElse: SomethingElse?
override func clone() -> Self {
let clone = super.clone()
clone.somethingElse = somethingElse
return clone
}
}
However unfortunately, calling clone() on super returns an instance that's statically typed as Parent rather than Self – this has been filed as a bug.
To workaround this, you'll have to do some force casting hackery:
override func clone() -> Self {
let clone = super.clone() as! Child
clone.somethingElse = somethingElse
func forceCast<T>(_ value: Child) -> T { return value as! T }
return forceCast(clone)
}
The nested forceCast(_:) function is here to workaround the fact that we currently cannot directly cast to Self in a method (compare Return instancetype in Swift). Both the force casts in this case will always succeed because super.clone() will always return a Self instance, which therefore must be a Child in this method.

Swift: How to add a class method in 'String" extension

I want to add a class function into extension:
extension String {
class func test () {
}
}
I get the error: Class methods are only allowed within classes; use 'static' to declare a static method
Or how should i call " String.test()"
But for NSString
extension NSString {
class func aaa () {
}
}
no errors.
If i add static keyword:
extension String {
static func aaa () {
self.stringByAppendingString("Hello")
}
}
Got: Expression resolves to an unused function,
So how should i add a class function also want to use self. method.
EDIT: This works!
extension String {
static func aaa (path:String) -> String {
return path.stringByAppendingString("Hello")
}
}
but about #lan's answer:
mutating func bbb(path: String) {
self += "world"
}
When i type it appears like this:
String.bbb(&<#String#>)
String.bbb(&"nihao")
Cannot invoke 'bbb' with an argument list of type '(String)'
Class and static functions are not called on an instance of a class/struct, but on the class/struct itself, so you can't just append a string to a class.
Apple Documentation:
Within the body of a type method, the implicit self property refers to
the type itself, rather than an instance of that type.
You can, however, append a string to a variable instance of a String using the mutating keyword:
extension String {
mutating func aaa() {
self += "hello"
}
}
let foo = "a"
foo.aaa() // ERROR: Immutable value of type 'String' only has mutating members named 'aaa'
var bar = "b"
bar.aaa() // "bhello"
If you are trying to use a pointer to a string as a parameter, you can use the inout keyword to alter the inputed string:
extension String {
static func aaa(inout path: String) {
path += "Hello"
}
}
var foo = "someText"
String.aaa(&foo)
foo //someTextHello
While correct, it's somewhat atypical to see a mutating member added to a String extension as shown in Ian's answer. Strings (and value types in general) are meant to be immutable so the only way to use a mutating method is to declare instances var at the call site. Most of the time in your code you should be using let constants.
As such, it is much more common to extend structs to return new instances. So this is typical:
extension String {
func appending(_ string: String) -> String {
return self + string
}
}
and then at the call site:
let hello = "Hello, "
let helloWorld = hello.appending("World!")
You'll note of course that I'm not using static at all. That's because appending(_:) needs to use the current instance value of the String we're appending to, and class/static do not refer to instances and therefore do not have values.
"Within the body of a type method, the implicit self property refers to the type itself, rather than an instance of that type."
Thus when you extend a type by adding a type method you can only call other type methods through self. If you want to call an instance method you need to create an instance and call a method on that.

Call Class Methods From Protocol As Parameter

I want to be able to pass a class (not an initialized object) of a certain protocol type to a method, then call the class functions of that class in the method. Code below.
I am using Swift and have an protocol defined like this
//Protocol for any object to be used with an FAUAPIConnection
protocol FAUAPIModel{
//Used to parse the object from a given dictionary to an object
class func parseFromJSON(JSON:AnyObject) -> Self
//Required default init
init()
}
What I would like to do is have a method like this
func getSomeParsingDone<T:FAUAPIModel>(model:T.Type? = nil, getPath:path, callingObj:CallingClass) -> Void
{
//GetIt is inconsequential, just logic to get an object from a certain path
var returnObj:AnyObject = GetIt.get(path)
if(model != nil){
returnObj = model!.parseFromJSON() <<<<<< Type 'T' does not conform to protocol 'AnyObject'
}
callingObj.done(returnObj)
}
Object that implements the protocol
import Foundation
class MyObj: FAUAPIModel{
var neededVal:String
var nonneededVal:String
required convenience init(){
self.init(neededVal:"VALUE")
}
init(neededVal:String, nonneededVal:String = ""){
self.neededVal = neededVal
self.nonneededVal = nonneededVal
}
class func parseFromJSON(JSON:AnyObject) -> WGMPart
{
return WGMPart() <<<<<<<< Method 'parseFromJSON' in non-final class 'WGMPart' must return 'Self' to conform to protocol 'FAUAPIModel'
}
}
However, I keep getting two errors. I have indicated these above with '<<<<<<<<<<<<'
compile error.
Lots of little things to consider here, but let's get to the heart of your question. The signature you want looks like this:
func getSomeParsingDone<T:FAUAPIModel>(model:T.Type, path:String) -> T?
I'm making the return optional beause there are a lot of things that could fail here, and you really shouldn't turn all of those into crashes.
I'd recommend your protocol look like this:
protocol FAUAPIModel {
class func parseFromJSON(JSON:AnyObject) -> Self
}
That way, you're promising that your return your own class, not just anything that is parseable. That does tend to mean that you need to make your classes final. If you don't want them to be final, you'll need to promise some init method in order to construct it. See Protocol func returning Self for more details on how to deal with that if you need it.
So putting it together, it might look something like this in practice:
protocol FAUAPIModel {
class func parseFromJSON(JSON:AnyObject) -> Self
}
func createObjectOfClass<T: FAUAPIModel>(model: T.Type, path: String) -> T? {
if let json: AnyObject = GetJSON(path) {
return model.parseFromJSON(json)
}
return nil
}
// Bogus JSON reader
func GetJSON(path: String) -> AnyObject? {
let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(path.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)!, options: NSJSONReadingOptions(0), error: nil)
return json
}
// Bogus model class that returns trivial version of itself
final class Something: FAUAPIModel {
class func parseFromJSON(JSON:AnyObject) -> Something {
return Something()
}
}
// Using it
let something = createObjectOfClass(Something.self, "/path/to/file")
I just want to note that the answer to your exact question would be to declare your function like this:
func getSomeParsingDone(model:FAUAPIModel.Type? = nil, getPath:path) -> FAUAPIModel