Just like java's instanceOf keyword whats the equivalent in Swift?
java example:
A a = new A();
boolean isInstanceOfA = a instanceof A;
Here isInstanceOfA is true
So i need something similar in Swift
isKindOfClass() method, from NSObjectProtocol is the equivalent of java's instanceof keyword, in java it's a keyword but in swift it's a protocol method, but they behave similarly and are used in similar contexts.
isKindOfClass: returns YES if the receiver is an instance of the
specified class or an instance of any class that inherits from the
specified class.
Which is exactly what instanceof keyword does in Java related link
Example:
let a: A = A()
let isInstanceOfA: Bool = a.isKindOfClass(A) // returns true.
Also you can use the is keyword
let a: A = A()
let isInstanceOfA: Bool = a is A
The difference:
is works with any class in Swift, whereas isKindOfClass() works only with those classes that are subclasses of NSObject or otherwise implement NSObjectProtocol.
is takes a type that must be hard-coded at compile-time. isKindOfClass: takes an expression whose value can be computed at runtime.
So no is keyword doesn't work like instanceof
For swift3 and swift4 it's:
if someInstance is SomeClass {
...
}
if your class is extending NSObject you can also use:
if someInstance.isKind(of: SomeClass.self) {
...
}
let a = A()
let isInstanceOfA = a is A
For Swift 4.x it's:
func getOrElse<T>(defaultVal:T) -> T {
if let selfVal = self, selfVal is T {
return selfVal as! T
} else {
return defaultVal
}
}
Very short variant(by suggestion #Sulthan):
extension Optional {
func getOrElse<T>(defaultVal:T) -> T {
return (self as? T) ?? defaultVal
}
}
With objective-c it's isKindOfClass:[ClassName class].
With swift it's isKindOfClass(Classname.class()).
Related
I have a generic class that I want to be able to use with a default type. Right now I can initialize it with any type, but I have to be explicit.
//Initialize with a type
MyManager<MyCustomerObject>()
// Initialize with NSObject (what I want to be my default type)
MyManager<NSObject>()
// This doesn't work, but I want this kind of functionality
class MyManager<T = NSObject> {}
// So I can create my manager like so and it inserts the default type as NSObject
MyManager() //Or MyManager<>()
Is this possible in Swift?
There's no support for default generic arguments, but you can fake it by defining the default init() on a type-constrained extension, in which case the compiler will be smart enough to use that type. E.g.:
class MyManager<T> {
let instance: T
init(instance: T) {
self.instance = instance
}
}
extension MyManager where T == NSObject {
convenience init() {
self.init(instance: NSObject())
}
}
And now you can initialize the type with no argument and it will default to MyManager<NSObject>:
let mm1 = MyManager(instance: "Foo") // MyManager<String>
let mm2 = MyManager(instance: 1) // MyManager<Int>
let mm3 = MyManager() // MyManager<NSObject>
SwiftUI uses this technique quite a lot.
No, this currently isn't possible – although it is a part of the Generics Manifesto, so might be something that the Swift team will consider for a future version of the language.
Default generic arguments
Generic parameters could be given the ability to provide default
arguments, which would be used in cases where the type argument is not
specified and type inference could not determine the type argument.
For example:
public final class Promise<Value, Reason=Error> { ... }
func getRandomPromise() -> Promise<Int, Error> { ... }
var p1: Promise<Int> = ...
var p2: Promise<Int, Error> = p1 // okay: p1 and p2 have the same type Promise<Int, Error>
var p3: Promise = getRandomPromise() // p3 has type Promise<Int, Error> due to type inference
In the meantime however, a somewhat unsatisfactory compromise would be the use of a typealias:
class MyManager<T> {}
typealias MyManagerDefault = MyManager<NSObject>
let defaultManager = MyManagerDefault()
Not nearly as slick as just being able to say MyManager(), but it does show up next to MyManager in auto-complete, which is pretty handy.
If T is always a NSObject subclass, you can use a generic constraint in Swift 5.3:
class MyManager<T: NSObject> {
let t = T()
}
class MyCustomerObject: NSObject { }
let a = MyManager()
let b = MyManager<MyCustomerObject>()
I am using Swift 2.2 on XCode 7.3.1 and trying to call a Generic function from another Generic function.
Code
class Thing1 {
let variable: SomeProtocol
init<A: SomeProtocol>(variable: A) {
self.variable = variable
self.add1(self.variable)
}
func add1<A: SomeProtocol>(stuff: A) {
let thing: Thing2 = Thing2()
thing.add2(stuff)
}
}
class Thing2 {
func add2<A: SomeProtocol>(stuff: A) {
}
}
protocol SomeProtocol { }
add1("a") // Cannot invoke 'add1' with an argument list of type '(String)'
add1(4) // Cannot invoke 'add1' with an argument list of type '(Int)'
I get the error.
'Cannot invoke add with an argument of list type '(Whatever type I used to call the function)''
The problem is that abstract types in Swift don't necessarily conform to themselves – therefore you cannot use a SomeProtocol typed thing as a concrete typed thing that conforms to SomeProtocol (which is what your add1 generic function expects as an argument).
The simplest solution in your case therefore is just to use the generic variable argument, rather than the variable property, as because it's a generic, it's typed as a concrete thing that conforms to SomeProtocol, which can therefore be passed into your add1 function:
init<A: SomeProtocol>(variable: A) {
self.variable = variable
add1(variable)
}
However in order to prevent these kind of issues later down the line, you may want to consider making your class generic, assuming that your variable property should be of constant type throughout the lifetime of a given Thing1 instance:
class Thing1<A:SomeProtocol> {
let variable: A
init(variable: A) {
self.variable = variable
add1(variable)
}
func add1(stuff: A) {
let thing = Thing2()
thing.add2(stuff)
}
}
Or, you could refactor your code to use the abstract type SomeProtocol, which will allow you to work with any type that conforms to SomeProtocol (e.g allowing you to mix different Thing1 instances with different variable types in an array):
class Thing1 {
let variable: SomeProtocol
init(variable: SomeProtocol) {
self.variable = variable
add1(variable)
}
func add1(stuff: SomeProtocol) {
let thing = Thing2()
thing.add2(stuff)
}
}
class Thing2 {
func add2(stuff: SomeProtocol) {
}
}
Although you should always be aware of the extra costs that come with using abstract types, see this great WWDC talk for more info.
Adding the extensions to String and Int and constructing Thing1 objects makes it work:
extension String: SomeProtocol{}
extension Int: SomeProtocol{}
Thing1(variable: "a").add1("a")
Thing1(variable: 2).add1(4)
I'm trying to check if an object is of a given type and I'm getting an error:
'expectedClass' is not a type
My code below.
func testInputValue(inputValue: AnyObject, isKindOfClass expectedClass: AnyClass) throws {
guard let object = inputValue as? expectedClass else {
// Throw an error
let userInfo = [NSLocalizedDescriptionKey: "Expected an inputValue of type \(expectedClass), but got a \(inputValue.dynamicType)"]
throw NSError(domain: RKValueTransformersErrorDomain, code: Int(RKValueTransformationError.UntransformableInputValue.rawValue), userInfo: userInfo)
}
}
I'm trying to figure out what can be wrong here.
You should be able to do this with generics:
func testInputValue<T>(inputValue: AnyObject, isKindOfClass expectedClass: T.Type) throws {
guard let object = inputValue as? T else {
...
}
}
You should not do class comparisons with == as suggested in one of the other answers, unless you specifically want to test if the type of the object tested should exactly match the expected class and it is not allowed to be a subclass of the tested class.
You can use the instance method isKindOfClass to accomplish this, taking subclassing into account. See below for a code example.
NOTE: You may be surprised that this works on a pure Swift class type, given an instance method with the same name exists in NSObject / NSObjectProtocol. It does indeed work in pure Swift (as shown with the example code below – tested with Xcode 7.3, Swift 2.2.1), with no #objc types involved, as long as you import Foundation. I am presuming based on this that this instance method is added as an extension method in Foundation to all class types.
import Foundation
class A { }
class B { }
class C: B { }
enum ValueTestError: ErrorType {
case UnexpectedClass(AnyClass)
}
func testInputValue(inputObj:AnyObject, isKindOfClass expectedClass:AnyClass) throws {
guard inputObj.isKindOfClass(expectedClass) else {
throw ValueTestError.UnexpectedClass(inputObj.dynamicType)
}
}
let a = A()
let b = B()
let c = C()
do {
try testInputValue(c, isKindOfClass: B.self)
} catch {
print("This does not get printed as c is of type B (C is subclass of B).")
}
do {
try testInputValue(a, isKindOfClass: B.self)
} catch {
print("This gets printed as a is not of type B.")
}
Also, importantly although isKindOfClass is available as an instance method on AnyObject, trying to call it on an arbitrary Swift class typed object will only work if you first cast that object to AnyObject (which will always of course succeed). Example code illustrating this point is presented below, and there's more on this question over here.
import Foundation
class A {}
let a = A()
// the following compiles and returns 'true'
(a as AnyObject).isKindOfClass(A.self)
// the following fails to compile with "Value of type 'A' has no member 'isKindOfClass'"
a.isKindOfClass(A.self)
Not the greatest answer ever, but comparing with inputValue.dynamicType works:
if inputValue.dynamicType == expectedClass {
print("inputValue.dynamicType \(inputValue.dynamicType) equals expectedClass \(expectedClass)")
// ...
}
I am trying to build some mocking infrastructure, I want to be able to return a stubbed value and count the times the value was accessed. I have something simple like this:
class BasicMock<T> {
var callsCount = 0
private let backing: T
var result: T {
callsCount++
return backing
}
init(result: T) {
self.backing = result
}
}
class MockTimeDefinitionSerialiser: BasicMock<[String: [AnyObject]]>, TimeDefinitionSerialiserProtocol {
func serialiseTravelTime(travelTime: JSSTravelTime) -> [String: AnyObject] {
return result
}
}
However trying to build it:
let mockTimeDefinitionSerialiser = MockTimeDefinitionSerialiser(result: ["": ""])
Emits the error 'MockTimeDefinitionSerialiser' cannot be constructed because it has no accessible initialisers
My interpretation of the Swift docs is that I should automatically inherit the initialiser as I have set all stored properties.
What am I doing wrong?
Please remove any unnecessary code when asking a question. I was able to reduce your problem to this:
class Base<T> {
init(t: T) {}
}
class Sub: Base<Int> {}
Sub(t: 0) // error: 'Sub' cannot be constructed because it has no accessible initialisers
It seems like even though you specified the T in the subclass, the compiler cannot infer what the initialiser uses for T. I couldn't find a way to get the initialiser to be inherited, you'd have to use a workaround:
class Sub: Base<Int> {
override init(t: Int) {
super.init(t: t)
}
}
Given we have a Swift protocol with one static method:
protocol Creatable: class {
static func create() -> AnyObject
}
and a pure Swift class which conforms to the protocol:
class Foo : Creatable {
static func create() -> AnyObject {
return Foo() as AnyObject
}
}
Later on when one tries to make use of that protocol by operating on type Creatable e.g.:
var f : Creatable = Foo.self
f.create()
The compiler complains with the following:
error: type 'Foo.Type' does not conform to protocol 'Creatable'
The question is: is this a Swift limitation or I'm using the protocols and static/class method in the wrong way.
Objective-C equivalent would be something like:
Class someClass = [Foo class];
if ([someClass conformsToProtocol:#protocol(Creatable)]) {
[(Class <Foo>)someClass create];
}
A Creatable reference points to an instance of Foo, not to the Foo type itself.
To get the equivalent of the class-level protocol implementation, you need an instance of Creatable.Type:
let c: Creatable.Type = Foo.self
However, you’ll get an error when you then try to use it:
// error: accessing members of protocol type value 'Creatable.Type' is unimplemented
c.create()
All that said, is there a reason why you can’t just use functions to fulfill your requirement, instead of metatypes?
let f = Foo.create
// f is now a function, ()->AnyObject, that creates Foos
let someFoo = f()
Using .Type is the key:
var f : Creatable.Type = Foo.self
And this no longer gives the "unimplemented" error. See full code below:
protocol Creatable: class {
static func create() -> AnyObject
}
class Foo : Creatable {
static func create() -> AnyObject {
return Foo() as AnyObject
}
}
var f : Creatable.Type = Foo.self
f.create()