I'm trying to migrate my app to Swift 3 but I have troubles.
The code section that struggles me is:
extension JSON: Swift.BooleanType {
//Optional bool
public var bool: Bool? {
get {
switch self.type {
case .bool:
return self.object.boolValue
default:
return nil
}
}
set {
if newValue != nil {
self.object = NSNumber(value: newValue! as Bool)
} else {
self.object = NSNull()
}
}
}
On first line is where xCode throws an error:
extension JSON: Swift.BooleanType {
The error says: Inheritance from non-protocol type 'BooleanType' (aka 'Bool')
Does anybody know what's happening there?
Simplest solution is here,
Bad : extension JSON: Swift.BooleanType {
Good : extension JSON: {
Reason : Admittedly, I am using this to modify SwiftyJSON which is a framework for processing JSON data. In doing some research it seems that they didn't allow BooleanType to allow for inheritance. The suggested means of dealing with this is simply to remove the type.
link is given : https://forums.developer.apple.com/thread/53405
Protocols are Swift's equivalent of Java interfaces. If you've never worked with interfaces before, they're classes absent of any concrete implementation. They exist to describe the skeleton of a class (the attribute and method names it should have) without actually implementing them so that other classes that inherit from the interface can flesh them out later. In Swift they're particularly useful for implementing the Delegate pattern.
Boolean is not a protocol. It is very much a living, breathing concrete Type with an existing implementation. To do what you want to do you either need to override the existing get/set method for Boolean type or create your own Boolean type as described in the official Apple Swift Blog.
Related
I have the following function :
Amplify.API.query(request: .get(
self.getObjectForOCObject(ocObject: ocObject)!, byId: id)) { event in
The definition of the get function is :
public static func get<M: Model>(_ modelType: M.Type,
byId id: String) -> GraphQLRequest<M?> {
My getObjectForObject is as follows :
func getObjectForOCObject <M: Model>(ocObject:NSObject) -> M.Type?
{
if type (of:ocObject) == type(of: OCAccount.self)
{
return Account.self as? M.Type
}
return nil;
}
But I'm getting a"Generic Parameter 'M' could not be inferred. I get that the compiler cannot determine what type of object this is. However I don't know how to fix this. I need my getObjectForOCObject function to return what it is expecting. Essentially I'm trying to return the type of object based on the type of another object.
Normally this call is done this way and it works...
Amplify.API.query(request: .get(Account.self, byId: id)) { event in
I'm trying to avoid having to create a number of functions to handle each different Model in my code as that is being handled in higher up in the call hierarchy. Which is why I'm trying to do this. Otherwise I'm going to have to write essentially the same code in multiple places. In Objective C one can use the super class to pass objects around but the inheriting class still comes along with it. But with Swift being dynamically typed, I'm running into this issue.
The closest I've gotten is this... Changing the getObjectForOCObject return to Model.Type? as so :
func getObjectForOCObject (ocObject:NSObject) -> Model.Type?
{
if type (of:ocObject) == type(of: OCAccount.self)
{
return Account.self
}
return nil;
}
Then I get a Cannot convert value of type 'Model.Type?' to expected argument type 'M.Type' But aren't these essentially the same thing based on the .get function above?
Hoping for some insight here. Also, FYI, I'm pretty terrible with Swift so I'm certain I'm definitely doing some bad things in Swift here. I'm an expert with ObjC. I'm just trying to create a bridge between the two for this Swift library I'm using.
Since Swift 4, objects have gained subscript(keyPath:) which can be used to retrieve values using AnyKeyPath and its subclasses. According to the Swift book, the subscript is available on all types. For example, an instance of a class TestClass may be subscripted with an AnyKeyPath like so:
class TestClass {
let property = true
}
let anyKeyPath = \TestClass.property as AnyKeyPath
_ = TestClass()[keyPath: anyKeyPath]
This compiles correctly as expected. Use of any other valid subclass would also compile including PartialKeyPath<TestClass>, KeyPath<TestClass, Bool>, etc. This functionality is unavailable in a protocol extension. For example, the following is invalid:
class TestClass {
let property = true
}
protocol KeyPathSubscriptable {
}
extension KeyPathSubscriptable {
func test() {
let anyKeyPath = \TestClass.property as AnyKeyPath
_ = self[keyPath: anyKeyPath] // Value of type 'Self' has no subscripts
}
}
If we want to use that keyPath subscript in the protocol, we can include it in the protocol definition. However, the compiler will not resolve it automatically:
protocol KeyPathSubscriptable {
subscript(keyPath: AnyKeyPath) -> Any? { get }
}
extension KeyPathSubscriptable {
func test() {
let anyKeyPath = \TestClass.property as AnyKeyPath // This can be any valid KeyPath
_ = self[keyPath: anyKeyPath]
}
}
class TestClass: KeyPathSubscriptable { // Type 'TestObject' does not conform to protocol 'KeyPathSubscriptable'
let property = true
}
With this, we get a compile error: Type 'TestObject' does not conform to protocol 'KeyPathSubscriptable'. In order to resolve this, we must include a redundant implementation of that subscript in TestClass:
class TestClass: KeyPathSubscriptable {
let property = true
subscript(keyPath: AnyKeyPath) -> Any? {
fatalError() // This is never executed
}
}
This resolves the conformance issue and produces the goal result although it is seemingly unnecessary and illogical. I'm not sure how, but the subscript implementation is never even used. It's finding the expected implementation of subscript(keyPath:) and using that instead, but how? Where is that and is there any way to use it in a protocol? Why is this required by the compiler even though it's never used?
The context of this use case is in a logging module. The goal is that an object should be able to adopt a particular protocol which, with no additional setup on the object, would provide a human readable description of the object, instead of the default for many objects which is a memory address. The protocol would use Mirror to fetch KeyPaths of an object, read the values, and print them to the console. It is intended for debugging purposes and would not run in any production environment.
Please let me know if I can make any clarifications. I may post this to the Swift team if others think that this could potentially be a bug of sorts. All help is appreciated. Thanks in advance.
Full gist located here.
Situation
I have a two generic classes which will fetch data either from api and database, lets say APIDataSource<I, O> and DBDataSource<I, O> respectively
I will inject any of two class in view-model when creating it and view-model will use that class to fetch data it needed. I want view-model to work exactly same with both class. So I don't want different generic constraints for the classes
// sudo code
ViewModel(APIDataSource <InputModel, ResponseModel>(...))
// I want to change the datasource in future like
ViewModel(DBDataSource <InputModel, ResponseModel>(...))
To fetch data from api ResponseModel need to confirms to "Decodable" because I want to create that object from JSON. To fetch data from realm database it need to inherit from Object
Inside ViewModel I want to get response like
// sudo code
self.dataSource.request("param1", "param2")
If developer tries to fetch api data from database or vice-versa it will check for correct type and throws proper error.
Stripped out version of code for playground
Following is stripped out version of code which shows what I want to achieve or where I am stuck (casting un-constrained generic type to generic type that confirms to Decodable)
import Foundation
// Just to test functions below
class DummyModel: Decodable {
}
// Stripped out version of function which will convert json to object of type T
func decode<T:Decodable>(_ type: T.Type){
print(type)
}
// This doesn't give compilation error
// Ignore the inp
func testDecode<T:Decodable> (_ inp: T) {
decode(T.self)
}
// This gives compilation error
// Ignore the inp
func testDecode2<T>(_ inp: T){
if(T.self is Decodable){
// ??????????
// How can we cast T at runtime after checking T confirms to Decodable??
decode(T.self as! Decodable.Type)
}
}
testDecode(DummyModel())
Any help or explanation that this could not work would be appreciated. Thanks in advance :)
As #matt suggests, moving my various comments over to an answer in the form "your problem has no good solution and you need to redesign your problem."
What you're trying to do is at best fragile, and at worst impossible. Matt's approach is a good solution when you're trying to improve performance, but it breaks in surprising ways if it impacts behavior. For example:
protocol P {}
func doSomething<T>(x: T) -> String {
if x is P {
return "\(x) simple, but it's really P"
}
return "\(x) simple"
}
func doSomething<T: P>(x: T) -> String {
return "\(x) is P"
}
struct S: P {}
doSomething(x: S()) // S() is P
So that works just like we expect. But we can lose the type information this way:
func wrapper<T>(x: T) -> String {
return doSomething(x: x)
}
wrapper(x: S()) // S() simple, but it's really P!
So you can't solve this with generics.
Going back to your approach, which at least has the possibility of being robust, it's still not going to work. Swift's type system just doesn't have a way to express what you're trying to say. But I don't think you should be trying to say this anyway.
In the method that fetch data I will check type of generic type and if it confirms to "Decodable" protocol I will use it to fetch data from api else from database.
If fetching from the API vs the database represents different semantics (rather than just a performance improvement), this is very dangerous even if you could get it to work. Any part of the program can attach Decodable to any type. It can even be done in a separate module. Adding protocol conformance should never change the semantics (outwardly visible behaviors) of the program, only the performance or capabilities.
I have a generic class which will fetch data either from api or database
Perfect. If you already have a class, class inheritance makes a lot of sense here. I might build it like:
class Model {
required init(identifier: String) {}
}
class DatabaseModel {
required init(fromDatabaseWithIdentifier: String) {}
convenience init(identifier: String) { self.init(fromDatabaseWithIdentifier: identifier )}
}
class APIModel {
required init(fromAPIWithIdentifier: String) {}
convenience init(identifier: String) { self.init(fromAPIWithIdentifier: identifier )}
}
class SomeModel: DatabaseModel {
required init(fromDatabaseWithIdentifier identifier: String) {
super.init(fromDatabaseWithIdentifier: identifier)
}
}
Depending on your exact needs, you might rearrange this (and a protocol might also be workable here). But the key point is that the model knows how to fetch itself. That makes it easy to use Decodable inside the class (since it can easily use type(of: self) as the parameter).
Your needs may be different, and if you'll describe them a bit better maybe we'll come to a better solution. But it should not be based on whether something merely conforms to a protocol. In most cases that will be impossible, and if you get it working it will be fragile.
What you'd really like to do here is have two versions of testDecode, one for when T conforms to Decodable, the other for when it doesn't. You would thus overload the function testDecode so that the right one is called depending on the type of T.
Unfortunately, you can't do that, because you can't do a function overload that depends on the resolution of a generic type. But you can work around this by boxing the function inside a generic type, because you can extend the type conditionally.
Thus, just to show the architecture:
protocol P{}
struct Box<T> {
func f() {
print("it doesn't conform to P")
}
}
extension Box where T : P {
func f() {
print("it conforms to P")
}
}
struct S1:P {}
struct S2 {}
let b1 = Box<S1>()
b1.f() // "it conforms to P"
let b2 = Box<S2>()
b2.f() // "it doesn't conform to P"
This proves that the right version of f is being called, depending on whether the type that resolves the generic conforms to the protocol or not.
I have a function:
func logLocalisedDescription(_ error: Any) {
NSLog(error.localizedDescription)
}
I want this to work for NSError and SKError, both of which have a localizedDescription, but no common superclass or protocol that declares it.
Is there a way to tell the Swift compiler to do run-time rather than compile-time type checking, like Objective-C's id? I tried Any, AnyObject and AnyClass, but none of them worked.
I'm fine with the code failing at runtime if the property doesn't exist.
Please don't suggest retrofitting classes to adopt protocols or other solutions. I'm aware of those. The question is about how to do dynamic typing in Swift.
Use a protocol :)
protocol LocalizedDescribable {
var localizedDescription: String { get }
}
extension NSError: LocalizedDescribable {}
extension SKError: LocalizedDescribable {}
func logLocalizedDescription(_ error: LocalizedDescribable) {
NSLog(error.localizedDescription)
}
You're asking about sending arbitrary Objective-C messages to an object of unknown type. I would call that dynamic messaging rather than dynamic type checking. In Objective-C, there are ways to make any object handle any message, regardless of the object's type.
Swift (on Apple platforms) allows you to do Objective-C-style dynamic messaging to AnyObject, as documented under “Accessing Objective-C Methods and Properties” in the AnyObject reference. In this case, here's the syntax:
func logLocalizedDescription(_ error: Any) {
if let d = (error as AnyObject).localizedDescription as String? {
NSLog("%#", d)
}
}
I had to explicitly specify the type of the message here to avoid an “Ambigious use of 'localizedDescription'” error, because there are multiple definitions of localizedDescription with different types (most are String, but Progress.localizedDescription is String!).
However, you don't need to use dynamic messaging in this particular case. The preferred Swift way, in this case, is to use as? Error, like this:
func logLocalizedDescription(_ error: Any) {
if let error = error as? Error {
NSLog("%#", error.localizedDescription)
} else {
NSLog("unknown error: %#", String(describing: error))
}
}
As it happens, SKError already conforms to Error, although it's not documented to do so. The above function will print an SKError's localizedDescription.
If you don't want to rely on this undocumented conformance, you can explicitly make it conform:
extension SKError: Error { }
Since Error declares localizedDescription, and SKError already implements localizedDescription, this retroactive conformance requires no implementation of its own.
Note also that it's inappropriate to pass an unknown string (like an error's localizedDescription) as the first argument of NSLog, because the first argument of NSLog is a format string. If the string contains unexpected % characters, the runtime behavior is undefined.
I think the type relationships are rather plain here and yet I'm missing the cause for the error. The error is: "Type 'T' does not conform to protocol 'EntityType'" (at ThingManager):
//
protocol EntityType {
typealias Identifier
var identifier : Identifier { get }
}
class EntityWithStringIdentifier : EntityType {
var identifier : String
init (i:String) { self.identifier = i }
}
class Thing : EntityWithStringIdentifier {}
//
protocol EntityManager {
typealias Entity : EntityType
func has (entity:Entity) -> Bool
}
class BaseEntityManager<Entity:EntityType> : EntityManager {
func has (entity:Entity) -> Bool { return true }
}
// Type 'T' does not conform to protocol 'EntityType'
class ThingManager<T:Thing> : BaseEntityManager<T> {
}
T is a subtype of Thing; Thing is a subtype of EntityWithStringIdentifier which implements EntityType. So, why the error?
Apparently the error is avoidable by using:
class ThingManager<T:Thing where T:EntityType> : BaseEntityManager<T> {
}
and then one can instantiate a ThingManager with Thing (implying Thing implemented EntityType in the first place...)
var tm = ThingManager<Thing>()
From a type perspective, is there a better way to implement this kind of DAO pattern?
With the announcement of Swift 2.0, it seems pointless to answer this question in terms of earlier versions of Swift, which will very soon be obsolete. I can confirm that this problem—which I believe to be a bug—still exists as of this writing in Swift 2.0. However, I can suggest a slightly different way to organize the code that mitigates the problem while still having a clean implementation: Skip the ThingManager class and use a protocol extension instead.
So, leaving all your code the same up to BaseEntityManager, you'd have:
// NOTE "where Entity: Thing". This is the key.
extension EntityManager where Entity: Thing {
func useAThing(thing: Thing) {
}
}
let tm = BaseEntityManager<Thing>()
tm.useAThing(Thing(i: "thing"))
I suspect this will end up being the "Swift way" of doing things. Swift's generics are just plain strange to me. They constantly violate the Principle of Least Surprise, IMHO. But ultimately they are quite powerful if you learn their quirks. The only drawback of this approach is with access modifiers and encapsulation. The useAThing method has no access to the private state of EntityManagerBase, which may or may not be a problem depending on your circumstances.
Lastly, if you take this approach, I recommend some renaming. BaseEntityManager feels like the wrong name if you never subclass it. Instead, I would call it EntityManager and rename the protocol to EntityManagerType to follow Apple's conventions.