How to convert Tuple to AnyObject in Swift - swift

Following piece of code compiles with error: Error:(112, 20) type '(String, Int)' does not conform to protocol 'AnyObject'
func myMethode() {
aMethodeThatICanNotChange {
let a = ("John",7)
return a // Error:(112, 20) type '(String, Int)' does not conform to protocol 'AnyObject'
}
}
func aMethodeThatICanNotChange(closure: () -> AnyObject) {
// do something with closure
}
How can I cast/convert a Tuple to AnyObject?

This is just a workaround.
You can create a class to wrap your tuple.
class TupleWrapper {
let tuple : (String, Int)
init(tuple : (String, Int)) {
self.tuple = tuple
}
}
Then you can write this:
func myMethod() {
aMethodeThatICanNotChange {
let a = ("John",7)
let myTupleWrapper = TupleWrapper(tuple: a)
return myTupleWrapper
}
}
Alternatively you can create a generic wrapper that can receive a value of any Type.
class GenericWrapper<T> {
let element : T
init(element : T) {
self.element = element
}
}
Hope this helps.

How can I cast/convert a Tuple to AnyObject?
Simply put, you can't. Only class types (or types that are bridged to Foundation class types) can be cast to AnyObject. A tuple is not a class type.
Of course there may be lots of other ways to accomplish whatever you're really trying to accomplish. But as for your particular question, you can't do it.

A tuple is an ordered list of elements, so you can transform it into an Array which conforms to AnyObject protocol
func myMethode() {
aMethodeThatICanNotChange {
// let a = ("John",7)
let b = ["Joth", 7]
return b // No error
}
}
func aMethodeThatICanNotChange(closure: () -> AnyObject) {
// do something with closure
}

Related

Generics and Protocols in Swift: Why does my $0 have no expectation member?

In the code below, when I try to let expectations = stuffToExpect.map({ $0.expectation }) the compiler says Value of tuple type '(key: _, value: HasExpectations)' has no member 'expectation'.
What is the correct way to use map in with a generic type?
import XCTest
import Foundation
protocol HasExpectations {
var expectation: XCTestExpectation { get }
}
public class A: HasExpectations {
var expectation: XCTestExpectation
init(expectation: XCTestExpectation) {
self.expectation = expectation
}
}
public class B: HasExpectations {
var expectation: XCTestExpectation
init(expectation: XCTestExpectation) {
self.expectation = expectation
}
}
func doit<T>(stuffToExpect: [T: HasExpectations]) {
let expectations = stuffToExpect.map({ $0.expectation })
}
</pre>
In your function
func doit<T>(stuffToExpect: [T: HasExpectations]) {
let expectations = stuffToExpect.map({ $0.expectation })
}
stuffToExpect is of type [T: HasExpectations] aka Dictionary<T: HasExpectations>. When you map over a dictionary it gives you a tuple of type (key: T, value: HasExpectations) back which is why you are seeing that error.
I think you instead wanted to constrain T instead and have stuffToExpect as an array, in which case the syntax is either of these (pick which you think looks best):
func doit<T: HasExpectations>(stuffToExpect: [T]) {
let expectations = stuffToExpect.map({ $0.expectation })
}
// or
func doit<T>(stuffToExpect: [T]) where T: HasExpectations {
let expectations = stuffToExpect.map({ $0.expectation })
}
You described Tas generic. That is correct. Now you want to say I am happy to accept any type T which conforms to protocol HasExpectations. That smeans <T: HasExpectation>.
So your function going to look like below
func doit<T: HasExpectations>(stuffToExpect: [T]) {
let expectations = stuffToExpect.map({ $0.expectation })
}
You got a compilation error because when you specify [T: HasExpections]. The compiler treats as a dictionary, which is not the case here.
Call mapValues over the expectation,
func doit<T>(stuffToExpect: [T: HasExpectations]) {
let expectations = stuffToExpect.mapValues { $0.expectation }
// here your expectations is a new dictionary of [Hashable: XCTestExpectation]
// also note that T is turned to Hashable since you cannot have stuffToExpect key with T, which is not actually Hashable.
// you can get all test expectations using values
let testExpectations = Array(expectations.values)
// here testExpectations is [XCTestExpectation]
}
My real problem was my function declaration:
func doit<T>(stuffToExpect: [T: HasExpectations]) {
What I really wanted to do was say that T conformed to HasExpectations:
func doit<T: HasExpectations>(stuffToExpect: [T: HasExpectations]) {

How to pass closure with argument as argument and execute it?

Initializer of class A takes an optional closure as argument:
class A {
var closure: ()?
init(closure: closure()?) {
self.closure = closure
self.closure()
}
}
I want to pass a function with an argument as the closure:
class B {
let a = A(closure: action(1)) // This throws the error: Cannot convert value of type '()' to expected argument type '(() -> Void)?'
func action(_ i: Int) {
//...
}
}
Class A should execute the closure action with argument i.
I am not sure about how to write this correctly, see error in code comment above. What has to be changed?
Please make your "what-you-have-now" code error free.
Assuming your class A like this:
class A {
typealias ClosureType = ()->Void
var closure: ClosureType?
init(closure: ClosureType?) {
self.closure = closure
//`closure` would be used later.
}
//To use the closure in class A
func someMethod() {
//call the closure
self.closure?()
}
}
With A given above, you need to rewrite your class B as:
class B {
private(set) var a: A!
init() {
//initialize all instance properties till here
a = A(closure: {[weak self] in self?.action(1)})
}
func action(i: Int) {
//...
}
}
The problem is that closure()? is not a type. And ()? is a type, but it is probably not the type you want.
If you want var closure to have as its value a certain kind of function, you need to use the type of that function in the declaration, e.g.
var closure: (Int) -> Void
Similarly, if you want init(closure:) to take as its parameter a certain kind of function, you need to use the type of that function in the declaration, e.g.
init(closure: (Int) -> Void) {
Types as Parameters
In Swift, every object has a type. For example, Int, String, etc. are likely all types you are extremely familiar with.
So when you declare a function, the explicit type (or sometimes protocols) of any parameters should be specified.
func swallowInt(number: Int) {}
Compound Types
Swift also has a concept of compound types. One example of this is Tuples. A Tuple is just a collection of other types.
let httpStatusCode: (Int, String) = (404, "Not Found")
A function could easily take a tuple as its argument:
func swallowStatusCode(statusCode: (Int, String)) {}
Another compound type is the function type. A function type consists of a tuple of parameters and a return type. So the swallowInt function from above would have the following function type: (Int) -> Void. Similarly, a function taking in an Int and a String and returning a Bool would have the following type: (Int, String) -> Bool.
Function Types As Parameters
So we can use these concepts to re-write function A:
class A {
var closure: (() -> Void)?
init(closure: (() -> Void)?) {
self.closure = closure
self.closure()
}
}
Passing an argument would then just be:
func foo(closure: (Int) -> Void) {
// Execute the closure
closure(1)
}
One way to do what I think you're attempting is with the following code:
class ViewController: UIViewController {
override func viewDidLoad() {
let _ = A.init(){Void in self.action(2)}
}
func action(i: Int) {
print(i)
}
}
class A: NSObject {
var closure : ()?
init(closure: (()->Void)? = nil) {
// Notice how this is executed before the closure
print("1")
// Make sure closure isn't nil
self.closure = closure?()
}
}

Using array of protocol in Swift class' generics

Is there any way to use array of protocol's generic?
For example,
/* I want to use protocol like below,
* but I can't because protocol is not concrete
* so cannot make array of it */
class MyClass<T where T:MyProtocol, T:[MyProtocol]> {
let result: T
}
protocol MyProtocol {
init(with: String)
}
class SpecialThing: MyProtocol {
let appleWatch: AppleWatch
init(with: String) {
self.appleWatch = AppleWatch(with)
}
}
class SampleClass {
func test {
typealias listCallback = (MyClass<[SpecialThing]>, NSError) -> ()
typealias oneCallback = (MyClass<SpecialThing>, NSError) -> ()
}
}
There can be one object or array of protocol's subclass.
I think "typealias" does not help me.
I want to find something more simple way.....
My first issue with this is that the type signature is wrong:
class MyClass<T where T:MyProtocol, T:[MyProtocol]>
That's the same type of thing as doing:
let t: String
let t: [String]
t = String("foo")
The compiler will complain because you are redefining T, once as a MyProtocol and again as an array of MyProtocol. You can't have both, you can only have one.
Answer: Use a construct like Either:
enum Either<T, U>
{
case Left(T)
case Right(U)
var leftValue: T?
{
if case .Left(let leftValue) = self
{
return leftValue
}
return nil
}
var rightValue: U?
{
if case .Right(let rightValue) = self
{
return rightValue
}
return nil
}
}
Allowing for:
class MyClass<T: MyProtocol>
{
let result: Either<T, [MyProtocol]>
}

Swift: Generics and type constraints, strange behavior

I can’t figure out how to perform a cast which would let me eventually to introduce some sort of dynamism working with generics.
Next piece of code does not compile. It shows this error:
Cannot invoke 'createContainer' with an argument list of type
'(FooProtocol)' Expected an argument list of type '(T)'
protocol FooProtocol {
func doSomething()
}
class Foo : FooProtocol {
func doSomething() {}
}
class Container<T : FooProtocol> {
let someDataConformingFooProtocol : T
init(someDataConformingFooProtocol : T) {
self.someDataConformingFooProtocol = someDataConformingFooProtocol
}
}
class AllTogether {
init () {
createContainer(Foo()) //So far, so good
let foo2Mask : AnyObject = Foo()
if let foo2MaskChecked = foo2Mask as? FooProtocol {
createContainer(foo2MaskChecked)
//ERROR: Cannot invoke 'createContainer' with an argument list of type '(FooProtocol)'
//Expected an argument list of type '(T)'
}
}
func createContainer<T : FooProtocol>(data: T){
Container<T>(someDataConformingFooProtocol: data)
}
}
Is this really the expected behaviour? Because personally I can’t understand what or why the compiler is complaining about it.
What would be the appropriate cast? Without referencing to the concrete class, I mean NOT like this:
if let foo2MaskChecked = foo2Mask as? Foo
Thanks!
What it comes down to is the difference between T: FooProtocol and FooProtocol as #Hamish mentioned in his comment.
When I have a function like this:
func foo(_ i: FooProtocol)
I'm taking in an instance of type FooProtocol, so I can pass in a value that conforms to FooProtocol or its type is FooProtocol. This is similar to subclassing where you can pass both SuperClass and SubClass into SuperClass.
But if you have a function like this:
func foo<T>(_ i: T) where T: FooProtocol
I can pass in any type that conforms to FooProtocol, but because FootProtocol does not conform to itself, you can't pass that in.
So in your question, you are trying to pass in a type FooProtocol where the types must conform to FooProtocol. You could probably fix this by doing:
class Container {
let someDataConformingFooProtocol: FooProtocol
init(someDataConformingFooProtocol: FooProtocol) {
self.someDataConformingFooProtocol = someDataConformingFooProtocol
}
}
// Later
func createContainer(data: FooProtocol){
Container(someDataConformingFooProtocol: data)
}

Extending the SequenceType in Swift

I wondered why map() and filter() in SequenceType return both an Array.
Actually, I don't think that's necessary. Returning a sequence again feels much more sensible to me.
However, I got stuck when trying to add sequential versions. Here's my attempt with map:
extension SequenceType {
func seqMap<T, S: SequenceType where S.Generator.Element == T>(
transform: Self.Generator.Element -> T) -> S
{
var sourceGen = generate()
let tGen: AnyGenerator<T> = anyGenerator {
if let el = sourceGen.next() {
return transform(el)
} else {
return nil
}
}
return AnySequence { tGen }
}
}
XCode tells me at the last return statement the following error:
cannot invoke initializer for type 'AnySequence<T>' with an argument list of type '(() -> AnyGenerator<T>)'
note: overloads for 'AnySequence<T>' exist with these partially matching parameter lists: (S), (() -> G)
Actually, my tGen is of type () -> G, so why does XCode think it is ambiguous?
The problem becomes more apparent if you split the return statement:
let tSeq = AnySequence { tGen }
return tSeq // error: cannot convert return expression of type 'AnySequence<T>' to return type 'S'
The compiler would infer the placeholder type S from the context
of a method call, and that could be any sequence
type with element type T, and not necessarily an AnySequence.
Here is a simple example demonstrating the same problem:
protocol MyProtocol { }
struct MyType { }
extension MyType : MyProtocol { }
func foo<P : Protocol>() -> P {
return MyType() // error: cannot convert return expression of type 'MyType' to return type 'P'
}
To solve the problem, change the return type to AnySequence<T>
and drop the generic type S:
extension SequenceType {
func seqMap<T>(transform: Self.Generator.Element -> T) -> AnySequence<T>
{
var sourceGen = generate()
let tGen: AnyGenerator<T> = anyGenerator {
if let el = sourceGen.next() {
return transform(el)
} else {
return nil
}
}
return AnySequence { tGen }
}
}
which can be written more compactly as
extension SequenceType {
func seqMap<T>(transform: Self.Generator.Element -> T) -> AnySequence<T>
{
var sourceGen = generate()
return AnySequence(anyGenerator {
sourceGen.next().map(transform)
})
}
}
using the map() method of the Optional type.
But note that SequenceType already has a lazy method which returns
a LazySequenceType:
/// A sequence containing the same elements as a `Base` sequence, but
/// on which some operations such as `map` and `filter` are
/// implemented lazily.
///
/// - See also: `LazySequenceType`
public struct LazySequence<Base : SequenceType>
and you can use
someSequence.lazy.map { ... }
to get a (lazily evaluated) sequence of the mapped values.