0

I am currently working on an iOS app using Swift. I have a custom DataSource that needs to know the Type of the model that it has to provide. I have a custom Protocol, that has one method.

protocol JSONModel {
    init(json: JSON)
}

Then, there are several models that implement the protocol. All of them have different properties, but are the same otherwise.

class CurrentDownload: JSONModel {

    let someProperty: String

    required init(json: JSON) {
        someProperty = json["someProperty"].stringValue
    }

}

My DataSource has a property that is of type JSONModel.Type

private let modelClass: JSONModel.Type

When i try to initialize a new instance of my modelClass i get a segmentation fault. Initialization of the model is done by

let model = modelClass(json: modelJSON)

Unfortunately, the compiler crashes on that line.

Swift Compiler Error
Command failed due to signal: Segmentation fault: 11
1.  While emitting IR SIL function 

@_TFC14pyLoad_for_iOS21RemoteTableDataSourceP33_56149C9EC30967B4CD75284CC9032FEA14handleResponsefS0_FPSs9AnyObject_T_ for 'handleResponse' at RemoteTableDataSource.swift:59:13

Does anybody have an idea on how to fix this or on how to work around this issue?

4
  • Try restarting xcode. Commented Apr 30, 2015 at 23:20
  • Thank you for your answer. I tried restarting Xcode, but unfortunately it did not fix my problem. Commented May 1, 2015 at 15:43
  • If you copied that piece of code from net, try rewriting it by hand. There could be BOM characters. Also optional values can cause this. Commented May 1, 2015 at 15:49
  • I did write that code on my own. I just copied it from Xcode to Stackoverflow and removed unnecessary bits. Commented May 1, 2015 at 17:37

1 Answer 1

1

I believe this problem isn't too hard.

Usually with Swift segmentation faults are when you try to set the value of a constant (let) quantity, or try to set the value of something that hasn't been properly declared.

I can spot one such instance here:

required init(json: JSON) {
   bytesLeft = json["someProperty"].stringValue
}

There's two things wrong with this example. You have a (designated) initialiser which terminates without setting the property someProperty and you haven't declared the variable bytesLeft.


So now the problem (which I really should have spotted before) is that * modelClass* just is not a class (or otherwise initialisable type). To cannot directly access a protocol, you can only access a class conforming to a protocol. The compiler didn't spot this because you did something sneaky with .Type.

When I say access, I mean functions and properties, including initialisers. Only a class can create an instance of a class, which has itself as the type of the instance, and protocols can't have bonafide instances themselves. If you think carefully about it, it is impossible to well-define what you are trying to do here. Suppose we had the protocol

 protocol JSONModel {
     init(json: JSON)
 }

but then two classes:

class CurrentDownload: JSONModel {
    let someProperty: String
    required init(json: JSON) {
        //Some other code perhaps.
        someProperty = json["someProperty"].stringValue
    }
}

class FutureDownload: JSONModel {
    let differentProperty: String
    required init(json: JSON) {
        //Different code.
        differentProperty = json["differentProperty"].stringValue
    }
}

whereas before one might argue that

JSONModel.Type(json: JSON)

(this code is equivalent to your code) should compile and run because we have given an implementation of init, we now can't deny that there is confusion - which implementation should we use here?? It can't choose one, and most would argue that it shouldn't try, and so it doesn't.

What you need to do is initialise with some class. If you are looking for a minimal class that adheres to JSONModel and no more, you'll need to write such a class e.g.

class BasicJSONModel: JSONModel {
    let someProperty: String
    required init(json: JSON) {
        //Some other code perhaps.
        someProperty = json["someProperty"].stringValue
    }
}

Then do

private let modelClass: BasicJSONModel//.Type not needed with a class

let model = modelClass(json: modelJSON)

of course this is probably silly and one may just write

let model = BasicJSONModel(json: modelJSON)

Or you could just write a common superclass if the protocol's only use is for this:

class SuperJSONModel {
    let someProperty: String//This is not needed of course and you could just strip down to the init only.
    init(json: JSON) {
        //Some other code perhaps.
        someProperty = json["someProperty"].stringValue
    }
}

and then is you wanted to check that some object is "conforming" to the what was the JSONModel, you simply check that it is a subclass of SuperJSONModel.

Sign up to request clarification or add additional context in comments.

9 Comments

Thank you very much for your answer. Unfortunately, the error you spottet only happend when copying the source to stackoverflow. That error is not there in my code. I improved my original question to fix that. Sorry about that!
Had another look. There you go. ^ :)
Thank you for your extensive answer. I now use a common superclass and everything works as expected. However, there are some annoyances with this approach. 1) All subclasses do have to call super.init(json: json) in their initializers. 2) There is a superclass with an empty initializer and someone could initialize that very superclass. The superclass should be abstract and never be initialized directly.
As your solution comes comes very close to what i searched for and I don't have a nicer solution, i will accept your answer!
Thanks for the tick :) So regarding (1), yes, that can't really be avoided. Why don't you just have a protocol as you did originally and then just don't have any kind of abstract superclass? Regarding (2), if you don't want an abstract superclass with common properties then why did you ever want to initialise a common protocol/class with the modelClass(json: modelJSON)?
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.