cannot specialize a non-generic definition - ios

I have tried following Cannot explicitly specialize a generic function and I can't get a hold of this
This is my code
class A<T>{
func test(){
self.verify(value : T.self)
}
func verify<T>(value: T) {
print("Default")
}
}
extension A where T == String {
func verify<T>(value: T){
print("Str")
}
}
let o = A<String>()
o.test()
The test is the only available function that can be called. When I'm executing this, I get
Default not Str.
But according to the generics, I should get Str. What am I doing wrong here? What should I do to keep extension A give me Str if T == String

Ok, so I'm learning generics new here. And this is what I got,
class A<T>{
func test(){
print("Def Test")
verifyVal()
}
func verify() {
print("Default verifyVal")
}
}
extension A where T == String {
func test(){
print("String")
}
}
extension A where T == Int {
func test(){
print("Int")
}
}
let o = A<String>()
o.test()
let a = A<Int>()
a.test()
This will give you the expected result
String
Int
So basically overload the test method instead of verify.
However, there are some caveats
If the method test is inherited from another class , say A is a child of N where the method test was originally written, there is no way you can override it in the extensions.
Thats it.

Related

Is it possible to provide a default value for a template function argument?

Consider the following code:
protocol Foo {
func f() -> Void
}
class Bar1: Foo {
func f() {
print("Bar1 f")
}
}
class Bar2: Foo {
func f() {
print("Bar2 f")
}
}
func function<T:Foo>(arg:T = Bar2()) {
arg.f()
}
It gives an error Value of type Bar2 cannot be converted to type T, which seems to be pure nonsense, because T is guaranteed to be compatible with Foo and this is the context within which the assignment should operate.
To prove it:
let global: Foo = Bar2()
global.f()
This works just fine.
I am wondering why such a discrepancy exists and if there is any workaround for it?
Cast the Bar2() as Generic type T
func function<T:Foo>(arg:T = Bar2() as! T) {
arg.f()
}

Swift nested class as mocks

I would like to use nested classes in Swift for mocking purposes. Imagine bar() method of following Foo class is under the test:
class Foo: NSObject {
func baz() -> String {
return "baz"
}
func bar() -> String {
return self.baz().stringByReplacingOccurrencesOfString("z", withString: "r")
}
}
I want to mock baz() method and verify that bar() depends on it with following test:
class FooTests: XCTestCase {
func testBar() {
class FooMock: Foo {
override func baz() -> String {
return "zzz"
}
}
let mock = FooMock()
let result = mock.bar()
XCTAssertEqual("rrr", result)
}
}
I have Foo class added to both application and test targets to bypass access modifiers issue with test target.
The application fails to compile with below error:
Global is external, but doesn't have external or weak linkage!
%4* (%0*, i8*)* #_TToFCFC13TestTestTests8FooTests7testBarFS0_FT_T_L_7FooMock3bazfS1_FT_SS
invalid linkage type for function declaration
%4* (%0*, i8*)* #_TToFCFC13TestTestTests8FooTests7testBarFS0_FT_T_L_7FooMock3bazfS1_FT_SS
LLVM ERROR: Broken module found, compilation aborted!
After moving FooMock to separate source file it compiles and works just fine.
When using nested class to mock any methods from iOS standard frameworks it works just fine:
func testMockDefaults() {
class NSUserDefaultsMock: NSUserDefaults {
override func objectForKey(defaultName: String) -> AnyObject? {
return "Super secret!"
}
}
let defaults = NSUserDefaultsMock(suiteName: "SuiteName")!
defaults.setObject("Test", forKey: "Test")
let result = defaults.objectForKey("Test") as String
XCTAssertEqual("Super secret!", result)
}
Could you please explain me what am I missing and what is the reason behind this?

superclass methods to return subclass type in swift

I have this code:
class Dark: NSObject {
class var className: String {
return NSStringFromClass(self)!.componentsSeparatedByString(".").last!
}
var success = 0
class func devour<T: Dark>(params: Int) -> T {
var s = T()
return assign(s, params: params)
}
class func assign<T: Dark>(item: T, params: Int) -> T{
if item.dynamicType === self {
item.success = params
}
return item
}
}
class Black: Dark {
}
class Violet: Dark {
}
Black.className // returns "Black"
Violet.className // returns "Violet"
The problem occurs when I do this:
var ret = Black.devour(5)
ret.success //returns 0 which I expect to be 5
ret.self // returns {Dark success 0} which I expect to be {Black success 0}
The problem here is that when the subclass uses the inherited method devour, it returns an object of type Dark. I want to be able to return the subclass type and not the superclass type when calling devour. Example when I do:
var ret = Black.devour(5)
The class of ret should be of class Black and not of class Dark.
I hope someone can help me on this. Im really out of ideas. Thanks!
I want to avoid chaining and I consider it last resort.
It turns out I was able to do a work around; Thanks to the answer to this question: Cast to typeof(self).
All I need to do is create a method which returns an object of type Self.
first, I created a class that creates an instance of the base class and return it as an instance of AnyObject.
class func createDark() -> AnyObject {
var black = Black()
return black
}
When I return an instance of Black it automatically casts it into AnyObject since it was the specified return type of the method (I honestly just figured this out and this saved me).
Then I created a helper method that calls createDark() and assigns properties/attributes to the instance:
class func prepare<T: Dark>(params: Int) -> T{
var dark = createDark() as T
dark.assign(params)
return dark
}
I used generic type which is of Dark type or its subclass as a return type.
Then I did this:
class func devour(params: Int) -> Self {
return prepare(params)
}
by specifying Self as return type, It automatically casts it to type of self which can be of Dark type or any class that inherits it.
My final code looks like this:
class Dark: NSObject {
var success = 0
func assign(params: Int) {
if self.dynamicType === self { // I dont really have to do this anymore
self.success = params
}
}
class var className: String {
return NSStringFromClass(self)!.componentsSeparatedByString(".").last!
}
class func createDark() -> AnyObject {
var black = Black()
return black
}
class func prepare<T: Dark>(params: Int) -> T {
var dark = createDark() as T
dark.assign(params)
return dark
}
class func devour(params: Int) -> Self {
return prepare(params)
}
}
to check if it solved the problem:
var ret = Black.devour(5)
ret.success //now returns 5 as expected
ret.self // now returns {Black success 0} as expected
works as expected!

Swift: how to return class type from function

I know it is possible to pass class type to a function in swift:
func setGeneric<T>(type: T.Type){ }
setGeneric(Int.self)
But how we can return type from function? Writing something like
func getGeneric<T>() -> T.Type {
return Int.self
}
gives compiler error "Int is not identical to T". So is it possible to return type from a swift function?
Edit
Some explanation. I have classes that are used for persistence (I'm using Realm) and I have classes that acts as wrappers around this classes. All wrappers inherits from RealmClassWrapper which needs to know what Realm class it actually wraps. So lets say I have this realm model:
class RealmTodo: RLMObject {
dynamic var title = ""
}
and my wrappers supper class looks like this:
class RealmClassWrapper {
private let backingModel: RLMObject
//...
func backingModelType<T>() -> T.Type{ fatalError("must be implemented") }
}
and actual wrapper:
class Todo: RealmClassWrapper {
//some other properties
func backingModelType<T>() -> T.Type{ return RealmTodo.self }
}
You can return any type you want.
func getTypeOfInt() -> Int.Type { return Int.self }
func getTypeOfBool() -> Bool.Type { return Bool.self }
If the type is not determined from arguments or if the return is constant, there is no need to introduce a generic T type.
It works when I modify your function like this:
func getGeneric<T>(object: T) -> T.Type {
return T.self
}
getGeneric(0) // Swift.Int
You can force the downcast (as!) as below
func getGeneric<T>() -> T.Type {
return Int.self as! T.Type
}
But out of the function scope, you need to indicate the returned type:
var t:Int.Type = getGeneric()
Yes, this is possible. The problem here is that you say your function returns a generic T.type, but you always return Int.type. Since T is not always an Int, the compiler raises an error.
If you don't want to specify the return type you can use AnyClass as it instead of a template parameter.
class A {}
class B {}
public enum ExampleEnum: String {
case a
case b
func asClass() -> AnyClass {
switch self {
case .a:
return A.self
case .b:
return B.self
}
}
}
let myGoal : AnyClass = ExampleEnum.a.asClass()
You can also avoid the final cast to AnyClass, but compiler will show you an error

Check if AnyObject is of generic type in Swift

Let's say that I have generic class Bus:
class Bus<T> {
func doSomething() {}
}
and I can create instance of it:
var myBus = Bus<String>()
Now I have a function that takes one parameter of the AnyObject and tests it's type:
func checkType(object: AnyObject) {
if let foo = object as? String {
println("string")
}
}
My problem is that I can't see a way to check if object is of type Bus and run function doSomething() if it is of type Bus. Any help would be appreciated.
Edit: Protocols also don't seem to solve this the way they should.
import Foundation
#objc protocol BusProtocol {
func doSomething() -> Void
}
class Bus<T> : BusProtocol {
func doSomething() -> Void {
println("asdf")
}
}
func checkType(object: AnyObject) {
if let foo = object as? Bus<AnyObject> {
foo.doSomething() // no match
}
if let foo = object as? Bus<Any> {
foo.doSomething() // no match
}
if let foo = object as? Bus<String> {
foo.doSomething() // prints "asdf"
}
if let foo = object as? BusProtocol {
foo.doSomething() // SIGABRT -- -[SwiftObject doesNotRecognizeSelector:]
}
}
checkType(Bus<String>())
The problem here is your thinking of Bus as a concrete thing. It really isn't. Bus<String> is. Bus<Int> is too. But Bus isn't, at least not in the same sense. You need to know what T is.
Really, what you want is to write something like this:
func checkType<T>(object: AnyObject) {
if let foo = object as? Bus<T> {
println("Bus<T>")
}
}
But if you try and use it, you'll get an error:
// error: Argument for generic parameter 'T' could not be inferred.
checkType(myBus)
Unlike in other languages, you can't write checkType<String>(myBus). But the following might do what you're looking for:
func checkType<T>(object: AnyObject, T.Type) {
if let foo = object as? Bus<T> {
println("Bus<T>")
}
}
checkType(myBus,String.self)
This fixes what T is for any Bus<T> and will work correctly.
You might object that you don't want to specify what T is. However, instead, this leads to the question... once you've figured out that object is some kind of Bus, what are you going to do then? Are you planning on calling methods on it, or passing it as an argument to other functions? Chances are what you're trying to achieve can be better done with a generic function and protocol constraints, rather than using AnyObject and casting.
In swift 2.x you can use a protocol to achieve this, as you attempted without error:
protocol Busish {
func doSomething() -> Void
}
class Bus<T> : Busish {
func doSomething() {
print(self)
}
}
func with_any_bus(obj:AnyObject) {
if let b = obj as? Busish {
b.doSomething()
}
}
with_any_bus(Bus<Int>());
with_any_bus(Bus<String>());
output:
swiftblah.Bus<Swift.Int>
swiftblah.Bus<Swift.String>
This may or may not be helpful to you specifically, since you seem to be using 1.2, but maybe someone else who stumbles on this question will find it useful.
You've practically got it.
func checkType(object: AnyObject) {
if let foo = object as? Bus<AnyObject> {
print("Got here")
} else {
print("Fail")
}
}
let bus = Bus<String>()
checkType(bus) // Fail
let otherBus = Bus<AnyObject>()
checkType(otherBus) // "Got Here"
I know that's not really what you want, but it shows what Swift needs.

Resources