is it possible to create a generic closure in Swift? [duplicate] - ios

This question already has answers here:
Closure with generic parameters
(2 answers)
Closed 7 months ago.
func myfunc<T>(i:T) -> T {
return i
}
is it possible to make this generic function a closure?
let myfunc = { <T>(i:T) -> T in
return i
}
this doesn't work...

No, because variables and expressions can't be generic. There are only generic functions and generic types.
To clarify: In some languages you can have types with a universal quantifier, like forall a. a -> a. But in Swift, types cannot have a universal quantifier. So expressions and values cannot be themselves generic. Function declarations and type declarations can be generic, but when you use such a generic function or an instance of such a generic type, some type (which could be a real type or a type variable) is chosen as the type argument, and thereafter the value you get is no longer itself generic.

Probably you need something like this.
Type declaration:
typealias ResultClosure<T> = (ResultCode, String?, T?) -> Void
Function declaration:
func loginUser(userName: String, password: String, resultHandler: ResultClosure<TokenModel>?)
Usage:
NetConnector.shared.loginUser(userName: userName ?? "", password: password ?? "") { (code, message, data) in
self.display?.unlockScreen()
if code == .success {
if let activeToken = data {
AppData.shared.userToken = activeToken
}
self.display?.showHome()
} else {
self.display?.showError(errorMessage: message)
}
}

As mentioned, variables in Swift cannot be generic, so creating a closure, whose generic types are specified by the caller is not possible. However, there are workarounds:
With SE-253, it is possible to make arbitrary (nominal) types callable. So instead of declaring a generic closure, we can declare a (non-generic) struct that has a generic callAsFunction method:
struct MyFunc {
func callAsFunction<T>(_ i: T) -> T {
return i
}
}
Now, we can declare a non-generic variable that we can call with a generic value:
let myFunc = MyFunc()
let x = myFunc(42) // -> Int
let y = myFunc("foo") // -> String
Note that this workaround doesn't apply to all situations, but it can be helpful in some.

I have found some alternative way , you can use Anyobject in your closure and pass any values to your method .
typealias genericCompletion<T:AnyObject> = ((Bool,T,String) -> Void)
struct Student {
var name:String = "Kishore"
var age : String = "125"
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.createAGenericReturn { (success, object, message) in
}
self.createStructGeneric { (success, student, message) in
}
}
func createAGenericReturn(callback:#escaping(genericCompletion<AnyObject>)){
callback(true,434.433 as AnyObject,"kishoreTest")
}
func createStructGeneric(callback:#escaping(genericCompletion<AnyObject>)){
callback(true,Student.init() as AnyObject,"kishoreTest")
}
}
Here you can see I mentioned Generic as Anyobject typealias genericCompletion = ((Bool,T,String) -> Void) , So you can pass any values to it .

Related

Testing type for class conformance in Swift

EDIT: The previous answers alluded to in the comments don't answer the question, which was how to determine if any given Type was a reference type and how to safely conform said type to AnyObject.
Testing against the passed type doesn't work, as the underlying type could be optional, or it could be a protocol, in which case one needs to know the passed instance is a class type or value type.
The solution I came up with is similar to the revised answer provided below.
So I have a new dependency injection framework, Factory.
Factory allows for scoped instances, basically allowing you to cache services once they're created. And one of those scopes is shared. Any instance shared will be cached and returned just as long as someone in the outside world maintains a strong reference to it. After the last reference releases the object the cache releases the object and a new instance will be created on the next resolution.
This is implemented, obviously, as simply maintaining a weak reference to the created object. If the weak reference is nil it's time to create a new object.
And therein lies the problem
Weak references can only apply to reference types.
Factory uses generics internally to manage type information. But I can create Factories of any type: Classes, structs, strings, whatever.)
Scopes use dictionaries of boxed types internally. If an instance exists in the cache and in the box it's returned. So what I'd like to do is create this...
private struct WeakBox<T:AnyObject>: AnyBox {
weak var boxed: T
}
The AnyObject conformance is need in order to allow weak. You get a compiler error otherwise. Now I want to box and cache an object in my shared scope with something like this...
func cache<T>(id: Int, instance: T) {
cache[id] = WeakBox(boxed: instance)
}
But this also gives a compiler error. (Generic struct WeakBox requires T to be a class type.)
So how to bridge from on to the other? Doing the following doesn't work. Swift shows a warning that "Conditional cast from 'T' to 'AnyObject' always succeeds" and then converts the type anyway.
func cache<T>(id: Int, instance: T) {
if let instance = instance as? AnyObject {
cache[id] = WeakBox(boxed: instance)
}
}
I'd be happy with the following, but again, same problem. You can't test for class conformance and you can't conditionally cast to AnyObject. Again, it always succeeds.
private struct WeakBox: AnyBox {
weak var boxed: AnyObject?
}
func cache<T>(id: Int, instance: T) {
if let instance = instance as? AnyObject {
cache[id] = WeakBox(boxed: instance)
}
}
What I'm doing at the moment is something like...
private struct WeakBox: AnyBox {
weak var boxed: AnyObject?
}
func cache<T>(id: Int, instance: T) {
cache[id] = WeakBox(boxed: instance as AnyObject)
}
Which works, but that instance as AnyObject cast depends on some very weird Swift to Objective-C bridging behavior.
Not being able to test for class conformance at runtime is driving me bonkers, and seems like a semi-major loophole in the language.
You can't test for conformance, and you can't cast for conformance.
So what can you do?
As Martin notes in a comment, any value can be cast to AnyObject in Swift, because Swift will wrap value types in an opaque _SwiftValue class, and the cast will always succeed. There is a way around this, though.
The way to check whether a value is a reference type without this implicit casting is to check whether its type is AnyObject.Type, like so:
func printIsObject(_ value: Any) {
if type(of: value) is AnyObject.Type {
print("Object")
} else {
print("Other")
}
}
class Foo {}
struct Bar {}
enum Quux { case q }
printIsObject(Foo()) // => Object
printIsObject(Bar()) // => Other
printIsObject(Quux.q) // => Other
Note that it's crucial that you check whether the type is AnyObject.Type not is AnyObject. T.self, the object representing the type of the value, is itself an object, so is AnyObject will always succeed. Instead, is AnyObject.Type asks "does this inherit from the metatype of all objects", i.e., "does this object which represents a type inherit from an object that represents all object types?"
Edit: Evidently, I'd forgotten that Swift includes AnyClass as a synonym for AnyObject.Type, so the check can be simplified to be is AnyClass. However, leaving the above as a marginally-expanded explanation for how this works.
If you want this method to also be able to handle Optional values, you're going to have to do a bit of special-casing to add support. Specifically, because Optional<T> is an enum regardless of the type of T, you're going to need to reach in to figure out what T is.
There are a few ways to do this, but because Optional is a generic type, and it's not possible to ask "is this value an Optional<T>?" without knowing what T is up-front, one of the easier and more robust ways to do this is to introduce a protocol which Optional adopts that erases the type of the underlying value while still giving you access to it:
protocol OptionalProto {
var wrappedValue: Any? { get }
}
extension Optional: OptionalProto {
var wrappedValue: Any? {
switch self {
case .none: return nil
case let .some(value):
// Recursively reach in to grab nested optionals as needed.
if let innerOptional = value as? OptionalProto {
return innerOptional.wrappedValue
} else {
return value
}
}
}
}
We can then use this protocol to our advantage in cache:
func cache(id: Int, instance: Any) {
if let opt = instance as? OptionalProto {
if let wrappedValue = opt.wrappedValue {
cache(id: id, instance: wrappedValue)
}
return
}
// In production:
// cache[id] = WeakBox(boxed: instance as AnyObject)
if type(of: instance) is AnyClass {
print("\(type(of: instance)) is AnyClass")
} else {
print("\(type(of: instance)) is something else")
}
}
This approach handles all of the previous cases, but also infinitely-deeply-nested Optionals, and protocol types inside of Optionals:
class Foo {}
struct Bar {}
enum Quux { case q }
cache(id: 1, instance: Foo()) // => Foo is AnyClass
cache(id: 2, instance: Bar()) // => Bar is something else
cache(id: 3, instance: Quux.q) // => Quux is something else
let f: Optional<Foo> = Foo()
cache(id: 4, instance: f) // => Foo is AnyClass
protocol SomeProto {}
extension Foo: SomeProto {}
let p: Optional<SomeProto> = Foo()
cache(id: 5, instance: p) // => Foo is AnyClass
So this took a while to figure out and even longer to track down the clues needed for a solution, so I'm providing my own code and answer to the problem
Given the following protocol...
private protocol OptionalProtocol {
var hasWrappedValue: Bool { get }
var wrappedValue: Any? { get }
}
extension Optional : OptionalProtocol {
var hasWrappedValue: Bool {
switch self {
case .none:
return false
case .some:
return true
}
}
var wrappedValue: Any? {
switch self {
case .none:
return nil
case .some(let value):
return value
}
}
}
And a box type to hold a weak reference...
private protocol AnyBox {
var instance: Any { get }
}
private struct WeakBox: AnyBox {
weak var boxed: AnyObject?
var instance: Any {
boxed as Any
}
}
Then the code to test and box a give type looks like...
func box<T>(_ instance: T) -> AnyBox? {
if let optional = instance as? OptionalProtocol {
if let unwrapped = optional.wrappedValue, type(of: unwrapped) is AnyObject.Type {
return WeakBox(boxed: unwrapped as AnyObject)
}
} else if type(of: instance) is AnyObject.Type {
return WeakBox(boxed: instance as AnyObject)
}
return nil
}
Note that the type passed in could be a class, or a struct or some other value, or it could be a protocol. And it could be an optional version of any of those things.
As such, if it's optional we need to unwrap it and test the actual wrapped type to see if it's a class. If it is, then it's safe to perform our AnyObject cast.
If the passed value isn't optional, then we still need to check to see if it's a class.
There's also a StrongBox type used for non-shared type caching.
struct StrongBox<T>: AnyBox {
let boxed: T
var instance: Any {
boxed as Any
}
}
And the final cache routine looks like this.
func resolve<T>(id: UUID, factory: () -> T) -> T {
defer { lock.unlock() }
lock.lock()
if let box = cache[id], let instance = box.instance as? T {
if let optional = instance as? OptionalProtocol {
if optional.hasWrappedValue {
return instance
}
} else {
return instance
}
}
let instance: T = factory()
if let box = box(instance) {
cache[id] = box
}
return instance
}
Source for the entire project is in the Factory repository.

How to create a nested Encodable class and return it from a function in Swift?

In my iOS project, I want to do the following:
create an Encodable class (named ChannelAnswer) which has multiple attributes, including another generic Encodable object
pass an instance of that class as an argument of a function or return it from a function
Here is what I tried:
class ChannelAnswer<T> : Encodable where T : Encodable
{
let errorCode: String?
let data: T?
let origin: Int = 2
init(_ errorCode: String?, _ data: T? = nil)
{
self.errorCode = errorCode
self.data = data
}
}
Now, if I want to return an instance of that class from a function, like the following:
func test() -> ChannelAnswer
{
...
return ChannelAnswer("abc", anyEncodableObject)
}
I get the following error:
Reference to generic type 'ChannelAnswer' requires arguments in <...>
The thing is: the data attribute could be of any type, I only know that that type is Encodable (the test()function above is just an example for the sake of simplicity).
So how can I create my ChannelAnswer class and successfully pass it as an argument of a function or return it from a function?
Thanks.
What you need is a generic method.
func test<T: Encodable>(data: T) -> ChannelAnswer<T> {
// ...
return ChannelAnswer("abc", data)
}

Issue with `Protocol can only be used as a generic constraint because it has Self or associated type requirements`

I'm trying to generate a ViewModel that conforms to a Protocol Protocoling, the protocol is generic, and has an associated type.
There are a few ViewModel's that conform to the protocol, so I am trying to create a factory for the viewModel.
I have encotuntered the following error by Swift:
Protocol can only be used as a generic constraint because it has Self or associated type requirements
Example code:
protocol Protocoling {
associatedtype modulingType
var data: modulingType { get }
}
enum MyTypes {
case myName
case myAddress
}
class NameViewModel: Protocoling {
let data: String
init(name: String) {
data = name
}
}
class AddressViewModel: Protocoling {
let data: [String]
init(address: [String]) {
data = address
}
}
class DataFactory {
func viewModel(forType type: MyTypes) -> Protocoling {
switch type {
case .name: return NameViewModel(name: "Gil")
case .address: return AddressViewModel(address: ["Israel", "Tel Aviv"])
}
}
}
The error is in func viewModel(forType type: MyTypes) -> Protocoling.
Is there a way to solve this issue?
You can use a protocol with an associated type (PAT) as a return type like that without more constraint because the compiler needs to know which type to use.
In your case you must use a technic called the type erasure to be able to work with any Protocoling:
class AnyProtocoling: Protocoling {
let data: Any
init<U: Protocoling>(_ viewModel: U) {
self.data = viewModel.data as Any
}
}
class DataFactory {
func viewModel(forType type: MyTypes) -> AnyProtocoling {
switch type {
case .myName:
return AnyProtocoling(NameViewModel(name: "Gil"))
case .myAddress:
return AnyProtocoling(AddressViewModel(address: ["Israel", "Tel Aviv"]))
}
}
}
This will allow you to "erase" the associated type of your protocol and return an Any version of your view model.
In order to understand why the PAT needs to work like that I like the following example: the Equatable protocol (which is a PAT):
static func ==(lhs: Self, rhs: Self) -> Bool
This function uses the Self type which is an associated type. You want to use it in the next generic function:
func areEquals(left: Equatable, right: Equatable) -> Bool {
return left == right
}
Here the compiler will trigger this error: Protocol can only be used as a generic constraint because it has Self or associated type requirements. Why? Lets take this example:
struct tomato: Equatable {}
struct salad: Equatable {}
areEquals(left: tomato(), right: salad())
There is no reason to compare tomatoes and salads. The associated type Self is not the same. To avoid this error in this case you need to constraint the Self type as following:
func areEquals<T: Equatable>(left: T, right: T) -> Bool
Now you know the T are equatables and with the same associated types.
This is very simple to fix, in your concrete factory implementation you just need to specify a generic for your factory that has to conform to protocol protocoling, see code below :
Swift 4
protocol Protocoling {
associatedtype modulingType
var data: modulingType { get }
}
enum MyTypes {
case myName
case myAddress
}
class NameViewModel: Protocoling {
let data: String
init(name: String) {
data = name
}
}
class AddressViewModel: Protocoling {
let data: [String]
init(address: [String]) {
data = address
}
}
class DataFactory<T> where T: Protocoling {
func viewModel(forType type: MyTypes) -> T? {
switch type {
case .myName: return NameViewModel(name: "Gil") as? T
case .myAddress: return AddressViewModel(address: ["Israel", "Tel Aviv"]) as? T
default: return nil /* SUPPORT EXTENSION WITHOUT BREAKING */
}
}
}
It's a first step into the wonderful world of abstraction with protocols. You really create some amazing things with it. Though, I have to say, that personally it's not as intuitive as something like inheritance, it's a great little mind bending puzzle for creating decoupled and abstract systems, that are actually far more powerful.
Swift is a great introductory language, and I believe that it's protocol and extension mechanisms make it one of the more complex and interesting languages.
This design pattern is a great way setting up things like dependency injection.

How to make generics in collection type constraint?

I have been trying to extract non-nil values from the String array. Like below. But, my senior wants it to be able to extract non-nil values from other types too.
I read, generics could help me for handling different types. How can I use generics so that I get to use following like extension to work with other types too?
getNonNil must return the extracted non-nil values of the specific type (i.e. if array is [String?] it must return [String], returns [Int] if [Int?])
Because I have to do further calculations.
What I have tried is below:
import Foundation
// Extended the collection-type so that collectiontype is constrained to having element with optional strings
extension CollectionType where Self.Generator.Element == Optional<String>{
func getNonNil() -> [String] {
// filter out all nil elements and forcefully unwrap them using map
return self.filter({$0 != nil}).map({$0!})
}
}
// Usage
let x: [String?] = ["Er", "Err", nil, "errr"]
x.getNonNil().forEach { (str) in
print(str)
}
For getNonNil you could simply use
x.flatMap { $0 }
// returns ["Er", "Err", "errr"] which is [String]
For the original question, typically you could introduce a protocol to the Optional type (e.g. via the muukii/OptionalProtocol package):
protocol OptionalProtocol {
associatedtype Wrapped
var value: Wrapped? { get }
}
extension Optional: OptionalProtocol {
public var value: Wrapped? { return self }
}
extension CollectionType where Self.Generator.Element: OptionalProtocol {
func getNonNil() -> [Self.Generator.Element.Wrapped] {
...
}
}
There's no easy way of achieving this through an extension, as you cannot introduce new generic types into extensions (although this is part of the Swift Generics Manifesto – so may well be possibly in a future version of Swift).
As #kennytm says, the simplest solution is just to use flatMap, which filters out nil:
x.flatMap{$0}.forEach { (str) in
print(str)
}
If however, you still want this as an extension, you could use a protocol workaround in order to allow you to constrain the extension to any optional element type (Swift 3):
protocol _OptionalProtocol {
associatedtype Wrapped
func _asOptional() -> Wrapped?
}
extension Optional : _OptionalProtocol {
func _asOptional() -> Wrapped? {return self}
}
extension Collection where Self.Iterator.Element : _OptionalProtocol {
func getNonNil() -> [Iterator.Element.Wrapped] {
return flatMap{$0._asOptional()}
}
}
...
let x : [String?] = ["Er", "Err", nil, "errr"]
x.getNonNil().forEach { (str) in
print(str)
}
(In Swift 3, CollectionType has been renamed to Collection, and Generator is now Iterator)
Although flatMap is almost certainly preferred in this situation, I'm only really adding this for the sake of completion.
The easiest approach is using flatMap as kennytm suggested, but if you absolutely want to know how to create such a method using generics, one approach would be to create a global method that takes in the collection as a parameter:
public func getNonNil<T, C: CollectionType where C.Generator.Element == Optional<T>>(collection: C) -> [T] {
return collection.filter({$0 != nil}).map({$0!})
}
let x: [String?] = ["Er", "Err", nil, "errr"]
print(getNonNil(x)) // returns ["Er", "Err", "errr"]

Swift: function overload resolution via closure parameter?

I am trying to solve a separate problem related to parsing JSON. In the process, I ran afoul of the Swift compiler, as I expected it to use closure template arguments to select a function overload for optional types.
I haven't seen anything explicit in their documentation on this topic, but is it not the expectation that all else equal, swiftc will use arguments of a closure parameter in a generic function to select the correct overload?
Here is the simplest sample that I could come up with:
import Foundation
let os:NSString = "foo!"
let d:[String:AnyObject] = ["a": os]
struct Model {
var opt:String?
var basic:String = ""
}
func read<T>(source:AnyObject?, set:T -> ()) {
if let t:T = source as? T {
println("basic: read type: \(T.self) from value \(source)")
}
else {
println("failed to read basic type \(T.self) from value \(source)")
}
}
func read<T>(source:AnyObject?, set:T? -> ()) {
assert(false, "this is not called")
if let t:T? = source as? T? {
println("optional: read optional type: \(T.self) from value \(source)")
}
else {
println("failed to read optional type \(T.self) from value \(source)")
}
}
var m = Model()
println(m)
let raw: AnyObject? = d["a"]
struct Property<T> {
typealias V = T
var get:() -> T
var set:T -> ()
func doRead(d:[String:AnyObject]) {
read(d["a"], set)
}
}
let b = Property(get: { m.basic }, set: { v in m.basic = v })
b.doRead(d)
let o = Property(get: { m.opt }, set: { v in m.opt = v })
o.doRead(d)
Per the comment inline, I expected the second overload to be used for optional types, but it is not. Am I missing something?
Edit
Note that the compiler is inferring the optional / non optional type from the property construct - it knows that the closure takes a optional, it just doesn't select the overload. I have restored some of my original logging code above, and the output is:
basic: read type: Swift.String from value Optional(foo!)
failed to read basic type Swift.Optional from value Optional(foo!)
From my usage of Swift, I see that the compiler prefers non-optionals over optionals. The operation:
let o = Property(set: { v in m.opt = v })
Is legal even when v is a non-optional, and therefore the compiler assumes as such.
This is a good question, and I assume a lot of other questions like this will be answered soon when Swift is made open-source.

Resources