There are two merge methods in RACSignal:
- (RACSignal *)merge:(RACSignal *)signal;
+ (RACSignal *)merge:(id<NSFastEnumeration>)signals;
When I write RACSignal.merge it references static method:
class func merge(signals: NSFastEnumeration!) -> RACSignal!
How to reference object method? I can't write self.merge, because it is in wrapper class and self is not RACSignal.
The curried class function and the curried instance function have
different signatures. Similarly as in
Swift - get reference to a function with same name but different parameters
you can refer to each by specifying the signature explicitly.
I have no experience with RACSignal, so here is an artificial
example that hopefully can be applied in your case:
class MyClass {
class func foo(s : String) {
println("class foo: \(s)")
}
func foo(s : String) {
println("instance foo: \(s)")
}
}
// Reference to the class method:
let f1 : String -> Void = MyClass.foo
// Call the class method:
f1("bar")
// Output: class foo: bar
// Reference to the instance method:
let f2 : MyClass -> String -> Void = MyClass.foo
// Call the instance method:
let obj = MyClass()
f2(obj)("bar")
// Output: instance foo: bar
As methods in Swift are curried class functions, compiler has to decide which overload to choose.
To reference instance's merge method you need to specify it's exact type:
let instanceMerge: RACSignal -> RACSignal! -> RACSignal! = RACSignal.merge
Related
I want to pass to setter as argument one of predefined functions (in enum maybe or static) or custom function in closure.
like UIColor to UIView.backgroundColor (i can set .black or UIColor(...)). How can I do it with my custom class?
class MyClass {
var fun: ((String)->Void)?
}
var obj = MyClass()
obj.fun = {print($0)} . // It works now
obj.fun = .predefinedFunc // It's how i want to be able do
What you seem to want to do is "implicit member access". Unfortunately, this is not possible on closure types like (String) -> Void, because it only works on enums, as well as types with static members. (String) -> Void doesn't and can't have any static members.
It seems like what you want is simply a bunch of predefined functions. This can be done with an enum:
enum Function {
case predefinedFunc1
case predefinedFunc2
case predefinedFunc3 // name these properly!
var closure: (String) -> Void {
switch self {
case .predefinedFunc1: return { print($0) }
case .predefinedFunc2: ...
case .predefinedFunc3: ...
}
}
}
And then you'll be able to do:
class MyClass {
var fun: Function?
}
var obj = MyClass()
obj.func = .predefinedFunc1
If you also want to include an option to use a custom function, add an extra case with an associated value:
enum Function {
...
case custom((String) -> Void)
var closure: (String) -> Void {
switch self {
case .predefinedFunc1: return { print($0) }
...
case .custom(let f): return f
}
}
}
view.backgroundColor = .black
works because black is a static property of struct UIColor. The right-hand side is called an “implicit member expression,” see for example What is the Swift syntax " .bar" called?.
Function types are neither classes nor structs, and you cannot define a static property for a function type. Therefore an identical syntax is not possible.
What you can do is to define a “wrapper” struct for the function, with static properties for the predefined functions. Here is a simple example:
struct Fun {
let f: (String) -> Void
init(_ f: #escaping (String) -> Void) {
self.f = f
}
// Predefined functions:
static var printer = Fun( { print($0) } )
// ...
}
class MyClass {
var fun: Fun?
}
And then you can do
let obj = MyClass()
obj.fun = Fun( { print($0) } ) // set to custom function
obj.fun = .printer // set to predefined function
This approach also allows to extend the wrapper type by more predefined functions:
extension Fun {
static var printReversed = Fun( { print($0.reversed()) } )
}
// ...
obj.fun = .printReversed
Please define the func same as you callback func or nameless fun, then you can pass it as an argument.
class MyClass {
var fun: ((String)->Void)?
}
//MARK:- you have to provide the same param and return type in your predefined func.
func printer(Str :String)->Void{
print(Str)
}
var obj = MyClass()
obj.fun = {print($0)}
obj.fun = printer
This question originates from reading the documentation around NSKeyedUnarchiver (documentation here) and it's instance method below:
func decodeDecodable<T>(_ type: T.Type, forKey key: String) -> T? where T : Decodable
What is the purpose of passing in _ type: T.Type when the type can already be determined from T?
Swift only allows you to explicitly specify generic parameters on types, not on methods or functions.
struct Foo<T> {
func bar<U>() -> U
}
let foo = Foo<Int>() // legal
foo.bar<Int>() // illegal
The language can infer T from the return value:
let foo = Foo<Int>() // legal
let bar: Int = foo.bar() // legal: T inferred to be Int
However, this is not always correct when using polymorphism.
class Bar {}
class Baz: Bar {}
let decoded: Bar = decodeDecodable(forKey: "baz")
// would infer decodeDecodable<Bar>(forKey: "baz")
// which is not correct for a Baz object
Please consider the following classes:
// Models:
class A {}
class B: A { }
// Parsers:
class AbstractParser<T> {}
class ParserB<T: B>: AbstractParser<T> {}
// Services:
class AbstractService<T> {
func parser() -> AbstractParser<T> {
fatalError("This method must be overridden")
}
}
class ServiceA<T: A>: AbstractService<T> {
}
class ServiceB<T: B>: ServiceA<T> {
private let _parser = ParserB()
override func parser() -> ParserB<B> {
return _parser
}
}
I'm getting an error Method doesn not override any method from it's superclasses at overriden parser function. I could easily fix this by changing
class ServiceB<T: B>: ServiceA<T>
to
class ServiceB<T: B>: ServiceA<B>
but this will break a solution from this question: A variable in generic class gets wrong type
Is there any workaround for this?
EDIT
Thanks, Kenneth Bruno, your approach works, but it again leads to another error with types.
I add class C:
class C {
var item = B()
}
and a simple method to ServiceB:
func doSomething() {
var entities = [T]()
let c = C()
entities.append(c.item)
}
This causes error: Cannot invoke 'append' method with an argument list of type '(B)'. It seems the compiler can't understand that B and T are the same thing?
Also please note that I can't define var entities = [B](), as I need to pass this array to another function in AbstractService method.
Just as in your other question you need to use the generic type instead of a specific type, then the method signatures will match to override the function.
class ServiceB<T: B>: ServiceA<T> {
private let _parser = ParserB<T>()
override func parser() -> ParserB<T> {
return _parser
}
}
From the question edit:
This causes error: Cannot invoke 'append' method with an argument list of type '(B)'. It seems the compiler can't understand that B and T are the same thing?
Just to clarify things. In the edit code example <T: B> and B are not the same thing. B is a regular type, while <T: B> is a generic type, which may represent a B type or any of it's subtypes.
Merging the question code with the code proposed by #Kenneth results in the following, which leads to a type error
class C {
var item = B()
}
class ServiceB<T: B>: ServiceA<T> {
private let _parser = ParserB<T>()
override func parser() -> ParserB<T> {
return _parser
}
func doSomething() {
var entities = [T]()
let c = C()
entities.append(c.item) // Error: Cannot invoke 'append' method with an argument list of type '(B)'
}
}
Now let's say in the future we add a new type D, subtype of B and instantiate a ServiceB<D>. This would cause the function doSomething() to try to append an instance of B in an array of D which is illegal, that's why the compiler raises an error.
With the code proposed in the comments by #Kenneth, the entities array would be filled in the ServiceB<B> case, but would always be empty in the ServiceB<D>.
class D: B { }
class ServiceB<T: B>: ServiceA<T> {
...
func doSomething() {
var entities = [T]()
let c = C()
if let item = c.item as? T { entities.append(item) }
}
}
let service = ServiceB<B>()
service.doSomething() // Creates an array of B and append a single B instance on it
let serviceD = ServiceB<D>()
serviceD.doSomething() // Creates an array of D, c.item of type B can't be cast to D, the array will be empty
While my answer doesn't really solves your problem, I think it should put you one step closer to a solution.
i have a question about swift and generics. What I try to do is to get an Object with an generic type. But I first know the type at runtime. But to get to the point fast.
New edited block:
Maybe I can do it with the class name? I have a class name as a string. I got it via a Mirror. Can I create a generic instance with that classname in an string?
let classname: String = "ClassA"
let firstA: a<classname> = a<classname>()
// ^^^^^^^^^ ^^^^^^^^^
// what to put here???
New edited block end:
I have two classes with generic types:
This is a protocol my type has to implement:
protocol ToImplement {
func getTypeForKey(key: String) -> NSObject.Type
}
This is the class I use for my first Generic Type:
class MyClass: ToImplement {
func getTypeForKey(key: String) -> NSObject.Type {
if key == "key1" {
return UIView.self
}
else {
return UIButton.self
}
}
}
this is my first Class with an generic type:
class a<T:ToImplement> {
func doSomethingWith(obj: T) -> T {
// the next part usually runs in an iteration and there can be
// a lot of different types from the getTypeForKey and the number
// of types is not known
let type = obj.getTypeForKey("key1")
let newA: a<type> = a<type>() // how could I do this? To create a type I do not know at the moment because it is a return value of the Object obj?
// ^^^^ ^^^^
// what to put here???
return obj
}
}
and that is how I would use it:
let mycls: MyClass = MyClass()
let firstA: a<MyClass> = a<MyClass>()
firstA.doSomethingWith(mycls)
Now my question is: Can I create an instance of class a with a generic type I get as a return value of a function? Is that even possible?
If that is not possible, how could I create an instance with an generic type out of an other instance. Something like:
let someA: a<instance.type> = a<instance.type>()
Thank you for your help!
regards
Artur
let type = obj.getType
OK, so type is a NSObject.Type. Since NSObject provides init(), you can instantiate this type with
let obj = type.init() // obj is a NSObject (or subclass)
return obj
Of course, this will fail at runtime if the actual type returned by getType() doesn't implement init().
Another option is to use an associated type:
protocol ToImplement {
typealias ObjType: NSObject
}
Then you can use it as a generic constraint:
func makeAnObject<T: ToImplement>(obj: T) -> T.ObjType {
return T.ObjType()
}
This gives basically the same result.
I have the following protocol and a class that conforms to it:
protocol Foo{
typealias BazType
func bar(x:BazType) ->BazType
}
class Thing: Foo {
func bar(x: Int) -> Int {
return x.successor()
}
}
When I try to create an Array of foos, I get an odd error:
var foos: Array<Foo> = [Thing()]
Protocol Foo can only be used as a generic constraint because it has
Self or associated type requirements.
OK, so it can only be used if it has an associated type requirement (which it does), but for some reason this is an error?? WTF?!
I'm not sure I fully understand what the compiler is trying to tell me...
Let's say, if we could put an instance of Thing into array foos, what will happen?
protocol Foo {
associatedtype BazType
func bar(x:BazType) -> BazType
}
class Thing: Foo {
func bar(x: Int) -> Int {
return x.successor()
}
}
class AnotherThing: Foo {
func bar(x: String) -> String {
return x
}
}
var foos: [Foo] = [Thing()]
Because AnotherThing conforms to Foo too, so we can put it into foos also.
foos.append(AnotherThing())
Now we grab a foo from foos randomly.
let foo = foos[Int(arc4random_uniform(UInt32(foos.count - 1)))]
and I'm going to call method bar, can you tell me that I should send a string or an integer to bar?
foo.bar("foo") or foo.bar(1)
Swift can't.
So it can only be used as a generic constraint.
What scenario requires a protocol like this?
Example:
class MyClass<T: Foo> {
let fooThing: T?
init(fooThing: T? = nil) {
self.fooThing = fooThing
}
func myMethod() {
let thing = fooThing as? Thing // ok
thing?.bar(1) // fine
let anotherThing = fooThing as? AnotherThing // no problem
anotherThing?.bar("foo") // you can do it
// but you can't downcast it to types which doesn't conform to Foo
let string = fooThing as? String // this is an error
}
}
I have been playing with your code trying to understand how to implement the protocol. I found that you can't use Typealias as a generic type because it is just an alias not a type by itself. So if you declare the Typealias outside your protocol and your class you can effectively use it in your code without any problem.
Note: the Typealias has the Int type in its declaration, that way you can always use the alias instead of the Int type and use all of its associated methods and functions.
Here's how I make it work:
typealias BazType = Int
protocol Foo{
func bar(x:BazType) -> BazType
}
class Thing: Foo {
func bar(x: BazType) -> BazType {
return x.successor()
}
}
let elements: Array<Foo> = [Thing(), Thing()]