I need to make a lazy array of my objects and process them later. For instance:
struct A {
init(i: Int) {
print(i)
}
}
let arrayA = (0..<3).lazy.map { A(i: $0) }
print(arrayA)
Outputs:
LazyMapSequence<Range<Int>, A>(_base: Range(0..<3), _transform: (Function))
The code from above works OK - neither init are called. But it changes when I try to use throwing initializer:
struct B {
init(i: Int) throws {
print(i)
}
}
let arrayB = try (0..<3).lazy.map { try B(i: $0) }
print(arrayB)
Outputs:
0
1
2
[__lldb_expr_92.B(), __lldb_expr_92.B(), __lldb_expr_92.B()]
As you can see all inits are called and the array is regular.
I haven't found any info about so my questions are:
Why does try force to convert from a lazy to a regular one (No throwing enumerator for collection etc.)?
Is it possible to make a lazy array with throw?
Simple workaround is wrapping throwing creation of your objects with throwing closures to postpone initialization and then you can operate lazy array of closures:
struct B {
init(i: Int) throws {
print(i)
}
}
let arrayB = (0..<3).lazy.map { i in { try B(i: i) } }
print(arrayB)
print(try arrayB[0]()) // Request first object
Outputs:
LazyMapSequence<Range<Int>, () throws -> B>(_base: Range(0..<3), _transform: (Function))
0
B()
Related
class A {
let val : Int
init(val: Int) {
self.val = val
}
}
I have these 3 strings:
let className = "A"
let argName = "val"
let argValue = "4"
How can I call A(val:4) from using these 3 strings?
Since you've noted in the comments that the types will all be subclasses of some supertype, then that supertype can handle all the dispatching. In Cocoa, this is a pretty common pattern known as a class cluster.
class SuperA {
enum SuperAError: Error {
case cannotConstruct
}
static func create(className: String, argName: String, argValue: String) throws -> SuperA {
switch className {
case "A":
guard argName == "val",
let value = Int(argValue)
else { throw SuperAError.cannotConstruct }
return A(val: value)
default:
throw SuperAError.cannotConstruct
}
}
}
Now, I don't particularly like this approach. This kind of subclassing tends to be poor Swift. Swift is fine with classes when you require a reference type, but it doesn't favor subclassing. I'd do this with a Buildable protocol and a Builder:
enum BuildableError: Error {
case unknownType
case badParameters
}
protocol Buildable {
init(argName: String, argValue: String) throws
// ... and the rest of the methods you require ...
}
struct A {
var val: Int
}
extension A: Buildable {
init(argName: String, argValue: String) throws {
guard argName == "val", let value = Int(argValue) else {
throw BuildableError.badParameters
}
self.init(val: value)
}
}
final class Builder {
var buildables: [String: Buildable.Type] = [:]
func build(className: String, argName: String, argValue: String) throws -> Buildable {
guard let buildable = buildables[className] else {
throw BuildableError.unknownType
}
return try buildable.init(argName: argName, argValue: argValue)
}
}
let builder = Builder()
builder.buildables["A"] = A.self
builder.build(className: "A", argName: "val", argValue: "4")
If this leads to duplicated code, there are straightforward ways to address that with other protocols. For example, if many of your types had init(val: Int), they could share code with another protocol:
protocol ValIntBuildable: Buildable {
init(val: Int)
}
extension ValIntBuildable {
init(argName: String, argValue: String) throws {
guard argName == "val", let value = Int(argValue) else {
throw BuildableError.badParameters
}
self.init(val: value)
}
}
extension A: ValIntBuildable {}
In native Swift alone, you can't. Swift is not dynamic in such a way that you can instantiate an arbitrary class based on a string name of the class, and so forth. Objective-C is dynamic and has ways to do this, so if this kind of thing is important to you, make A an NSObject subclass and write this part of the code in Objective-C (or use equivalent Cocoa/objc-runtime calls).
I’m trying to figure it out how to work with Objective-C Runtime.
There’s a class that has several methods defined through #objc extension. I want to get list of these methods with argument names and types. Something similar I get using print(#function, type(of: methodName)) - but this is in case if I call it inside this method, whereas I need to get all this stuff from outside.
I use class_copyMethodList and method_getName, but I get something like
method3WithArg1:arg2:
whereas #function and type(of: method) gives
method3(arg1:arg2:) (Int, Double) -> ()
method_getNumberOfArguments gives 2 more arguments, method_getArgumentType gives types like q, d, #. Last two I understand, but why q instead of f? (https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Strings/Articles/formatSpecifiers.html).
It would be better to get something familiar like method3(arg1: Int, arg2: Double). Question: do I have to do this manually or there are some other ways?
Further, I want to choose one method from the list, get parameters that it needs, assign that to chosenMethod variable, so that I could call it later. How do I make a closure from Selector? And do I need selectors at all?
Generally, there are some funcs in the class, some will be added later. User is asked to choose method from available, fill the arguments and simply call it.
class MyClass {
var chosenMethod: ((MyStruct) -> ())?
func execute() {
chosenMethod?(self)
}
}
#objc extension MyClass {
func method0() {
print(#function, type(of: method0), "\n")
}
func method1(_ arg1: String) {
print(#function, type(of: method1), "\n")
}
func method2(_ arg1: Int, _ arg2: Double) {
print(#function, type(of: method2), "\n")
}
func method3(arg1: Int, arg2: Double) {
print(#function, type(of: method3), "\n")
}
}
//extension MyStruct {
// #objc(arg1:arg2:) func method4(arg1: Int, arg2: Double) {
// print(#function, type(of: method4), "\n")
// }
//}
func getMethods() -> [Selector] {
var methodCount: UInt32 = 0
guard let methodList = class_copyMethodList(MyStruct.self, &methodCount) else { return [] }
var selectors = [Selector]()
let maxChars = 256
let ctype = UnsafeMutablePointer<Int8>.allocate(capacity: maxChars)
for i in 0 ..< Int(methodCount) {
let method = methodList[i]
let selector: Selector = method_getName(method)
selectors.append(selector)
print("name: \(String(cString: sel_getName(selector)))")
let numberOfArguments = method_getNumberOfArguments(method) - 2
print("numberOfArguments: \(numberOfArguments)")
for j in 2 ..< Int(numberOfArguments) + 2 {
method_getArgumentType(method, UInt32(j), ctype, maxChars)
print("argumentType: \(String(cString: ctype))")
}
print()
}
free(methodList)
return selectors
}
let myStruct = MyStruct()
myStruct.method0()
myStruct.method1("check")
myStruct.method2(0, 1.0)
myStruct.method3(arg1: 0, arg2: 1.0)
print("---\n")
let methods = getMethods()
myStruct.chosenMethod = { $0.method2(0, 1.0) }
//myStruct.chosenMethod = { $0.methods[1](0, 1.0) }
myStruct.execute()
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]) {
I have a method which does exactly the same thing for two types of data in Swift.
To keep things simple (and without duplicating a method) I pass AnyObject as an argument to my method which can be either of these two types. How to I unwrap it with an || (OR) statement so I can proceed? Or maybe this done otherwise?
func myFunc(data:AnyObject) {
if let data = data as? TypeOne {
// This works fine. But I need it to look something like unwrapping below
}
if let data = data as? TypeOne || let data = data as? TypeTwo { // <-- I need something like this
// Do my stuff here, but this doesn't work
}
}
I'm sure this is trivial in Swift, I just can't figure out how to make it work.
You can't unify two different casts of the same thing. You have to keep them separate because they are two different casts to two different types which the compiler needs to treat in two different ways.
var x = "howdy" as AnyObject
// x = 1 as AnyObject
// so x could have an underlying String or Int
switch x {
case let x as String:
print(x)
case let x as Int:
print(x)
default: break
}
You can call the same method from within those two different cases, if you have a way of passing a String or an Int to it; but that's the best you can do.
func printAnything(what:Any) {
print(what)
}
switch x {
case let x as String:
printAnything(x)
case let x as Int:
printAnything(x)
default: break
}
Of course you can ask
if (x is String || x is Int) {
but the problem is that you are no closer to performing an actual cast. The casts will still have to be performed separately.
Building on Clashsoft's comment, I think a protocol is the way to go here. Rather than pass in AnyObject and unwrap, you can represent the needed functionality in a protocol to which both types conform.
This ought to make the code easier to maintain, since you're coding toward specific behaviors rather then specific classes.
I mocked up some code in a playground that shows how this would work.
Hopefully it will be of some help!
protocol ObjectBehavior {
var nickname: String { get set }
}
class TypeOne: ObjectBehavior {
var nickname = "Type One"
}
class TypeTwo: ObjectBehavior {
var nickname = "Type Two"
}
func myFunc(data: ObjectBehavior) -> String {
return data.nickname
}
let object1 = TypeOne()
let object2 = TypeTwo()
println(myFunc(object1))
println(myFunc(object2))
Find if that shared code is exactly the same for both types. If yes:
protocol TypeOneOrTypeTwo {}
extension TypeOneOrTypeTwo {
func thatSharedCode() {
print("Hello, I am instance of \(self.dynamicType).")
}
}
extension TypeOne: TypeOneOrTypeTwo {}
extension TypeTwo: TypeOneOrTypeTwo {}
If not:
protocol TypeOneOrTypeTwo {
func thatSharedMethod()
}
extension TypeOne: TypeOneOrTypeTwo {
func thatSharedMethod() {
// code here:
}
}
extension TypeTwo: TypeOneOrTypeTwo {
func thatSharedMethod() {
// code here:
}
}
And here you go:
func myFunc(data: AnyObject) {
if let data = data as? TypeOneOrTypeTwo {
data.thatSharedCode() // Or `thatSharedMethod()` if your implementation differs for types.
}
}
You mean like this?
enum IntOrString {
case int(value: Int)
case string(value: String)
}
func parseInt(_ str: String) -> IntOrString {
if let intValue = Int(str) {
return IntOrString.int(value: intValue)
}
return IntOrString.string(value: str)
}
switch parseInt("123") {
case .int(let value):
print("int value \(value)")
case .string(let value):
print("string value \(value)")
}
switch parseInt("abc") {
case .int(let value):
print("int value \(value)")
case .string(let value):
print("string value \(value)")
}
output:
int value 123
string value abc
I'm trying to write a generic function in Swift with the constraint that the parameter must be a sequence of pairs (which I'm going to turn into a dictionary). Is this possible? I've tried a number of variations on the following, but the compiler doesn't like any of them.
func foo<K, V, S: SequenceType where S.Generator.Element == (K,V)>(xs: S) { //...}
Not a direct answer to your question, but if you want to create
a dictionary then you could define your function as an extension
method to Dictionary and use the fact that Dictionary defines
typealias Element = (Key, Value)
Then your method declaration could be
extension Dictionary {
func foo<S : SequenceType where S.Generator.Element == Element>(xs : S) {
//...
}
}
To create a dictionary from the tuples, an init method might be more appropriate, for example
extension Dictionary {
init<S : SequenceType where S.Generator.Element == Element>(xs : S) {
self.init()
var gen = xs.generate()
while let (key, value) : Element = gen.next() {
self[key] = value
}
}
}
Usage:
let d = Dictionary(xs: [("a", 1), ("b", 2)])
println(d) // [b: 2, a: 1]
Note: The enumation via generate() and next() in above code
is a workaround for the problem that, for some reason
for (key, value) in xs { }
does not compile. Compare Implementing Set.addSequence in Swift.
Update: As of Swift 2/Xcode 7, the above method can be simplified
to
extension Dictionary {
init<S : SequenceType where S.Generator.Element == Element>(xs : S) {
self.init()
xs.forEach { (key, value) in
self[key] = value
}
}
}
It looks like a compiler bug to me.
Problem here is that: you cannot use tuple type directly in generic parameters.
As #MartinR said in his answer, it works if we use typealiased tuple type. But of course, we cannot declare generic typealias in global context.
For example, this compiles and works:
struct Foo<K,V> {
typealias Element = (K,V)
static func foo<S:SequenceType where S.Generator.Element == Element>(xs:S) {
var gen = xs.generate()
while let (k,v): Element = gen.next() {
println((k,v))
}
}
}
Foo.foo(["test":"foo", "bar": "baz"])
One more idea is something like this:
struct SequenceOfTuple<K,V>: SequenceType {
typealias Element = (K,V)
let _generate:() -> GeneratorOf<Element>
init<S:SequenceType where S.Generator.Element == Element>(_ seq:S) {
_generate = { GeneratorOf(seq.generate()) }
}
func generate() -> GeneratorOf<Element> {
return _generate()
}
}
func foo<K,V>(xs:SequenceOfTuple<K,V>) {
for (k, v) in xs {
println((k,v))
}
}
foo(SequenceOfTuple(["test":"foo", "bar": "baz"]))
In this case, you must wrap the sequence of tuple with SequenceOfTuple type, then pass it to foo().
Hmm...
You can use a struct with a subscript and store the results in a Dictionary:
struct Matrix<K:Hashable, V> {
var container:[K:[K:V]] = [:]
subscript(x:K, y:K) -> V? {
get {
return container[x]?[y]
}
set (value) {
if container[x] == nil {
container[x] = [:]
}
container[x]![y] = value
}
}
}
var matrix = Matrix<Int, String>()
matrix[11,42] = "Hello World"
println("(11,42): \(matrix[11,42])") // Optional("Hello World")
println("(1,3): \(matrix[1,3])") // nil