I'm wondering if I can do something like this:
override func someCocoaFunc(someParameter:AnyObject?) {
if let parameter = someParameter as! Tuple {
let parameterType = parameter.1
if parameterType == "Heads up, this is an Int" {
print(parameter.0 + 1) //prints 2
}
else {
//fallback
}
}
}
let myTuple = (1,"Heads up, this is an Int")
someCocoaFunc(myTuple)
Obviously this doesn't work because Tuple is not a class, or at least not one I can cast to anyway. Is there a way to get this to work, if so how? If not, what is the best way to determine the type of an AnyObject? I tried:
if parameter is Bool {
//some code
}
else if parameter is Int {
//some code
}
But it doesn't seem to work, I think because Bool is just a typealias'd Int or something? So to summarize, can I use Tuples here, and if not, what should I do? To add some context, I'm writing one class that is used in serval different targets, so I can't be sure what the value will be, just that it is either an Int or Bool.
You cannot use tuples here because they are compound types and therefore no classes.
The problem with the if is that for compatibility Bool and Int get converted to NSNumber that has a boolValue and integerValue property which gets called if you cast them. So 0 and 1 is equivalent to true and false and therefore ambiguous.
As solution I would suggest to make a class which holds both values as Optionals:
class Holder {
let boolValue: Bool?
let intValue: Int?
}
Related
I have a function in Swift that returns Any? value and I would like to cast the result (based on the value type) to Bool, String or Int.
The function is this one:
static func value(forKey: SettingKeys) -> Any? {
return settingManager.settings.filter({$0.key == forKey.rawValue}).first?.value
}
and then when I do:
let printingEnabled = AppSettings().value(forKey:"printingEnabled") as? Int
i get NIL. Without the casting, the value is Optional("1"). Similar when I try casting results to String or Int. Any idea of how I could cast the result to a type of my choosing?
Thank you.
You don't want a function to return Any?. It is a nightmare of a type. Instead, you want to use generics to make sure the value is the type you want. For example:
static func value<T>(ofType: T.Type, forKey: SettingKeys) -> T? {
return settingManager.settings.filter({$0.key == forKey.rawValue}).first?.value as? T
}
Then this would be:
let printingEnabled = AppSettings().value(ofType: Int.self, forKey:"printingEnabled")
printingEnabled will in this case be Int?.
You can also, of course, wrap this up in helpers like:
static func int(forKey: SettingKeys) -> Int? {
return value(ofType: Int.self, forKey: forKey)
}
(BTW, while you definitely want to avoid Any? and use this kind of approach, I can't actually reproduce your issue. printingEnabled is Int? for me, and is Optional(1) as expected. I don't see any case where it's nil. But I can't make your code compile as written, either, since it's not clear what SettingKeys and settings are, so my code is probably significantly different than yours.)
In a Swift class, I want to use a property as a default parameter value for a method of the same class.
Here is my code :
class animal {
var niceAnimal:Bool
var numberOfLegs:Int
init(numberOfLegs:Int,animalIsNice:Bool) {
self.numberOfLegs = numberOfLegs
self.niceAnimal = animalIsNice
}
func description(animalIsNice:Bool = niceAnimal,numberOfLegs:Int) {
// I'll write my code here
}
}
The problem is that I can't use my niceAnimal property as a default function value, because it triggers me a compile-time error :
'animal.Type' does not have a member named 'niceAnimal'
Am I doing something wrong ? Or is it impossible in Swift ? If that's impossible, do you know why ?
I don't think you're doing anything wrong.
The language specification only says that a default parameter should come before non-default parameters (p169), and that the default value is defined by an expression (p637).
It does not say what that expression is allowed to reference. It seems like it is not allowed to reference the instance on which you are calling the method, i.e., self, which seems like it would be necessary to reference self.niceAnimal.
As a workaround, you could define the default parameter as an optional with a default value of nil, and then set the actual value with an "if let" that references the member variable in the default case, like so:
class animal {
var niceAnimal: Bool
var numberOfLegs: Int
init(numberOfLegs: Int, animalIsNice: Bool) {
self.numberOfLegs = numberOfLegs
self.niceAnimal = animalIsNice
}
func description(numberOfLegs: Int, animalIsNice: Bool? = nil) {
if let animalIsNice = animalIsNice ?? self.niceAnimal {
// print
}
}
}
I think for now you can only use literals and type properties as default arguments.
The best option would be to overload the method, and you can implement the shorter version by calling the full one. I only used a struct here to omit the initializer.
struct Animal {
var niceAnimal: Bool
var numberOfLegs: Int
func description(#numberOfLegs: Int) {
description(niceAnimal, numberOfLegs: numberOfLegs)
}
func description(animalIsNice: Bool, numberOfLegs: Int) {
// do something
}
}
I have this question except for Swift. How do I use a Type variable in a generic?
I tried this:
func intType() -> Int.Type {
return Int.self
}
func test() {
var t = self.intType()
var arr = Array<t>() // Error: "'t' is not a type". Uh... yeah, it is.
}
This didn't work either:
var arr = Array<t.Type>() // Error: "'t' is not a type"
var arr = Array<t.self>() // Swift doesn't seem to even understand this syntax at all.
Is there a way to do this? I get the feeling that Swift just doesn't support it and is giving me somewhat ambiguous error messages.
Edit: Here's a more complex example where the problem can't be circumvented using a generic function header. Of course it doesn't make sense, but I have a sensible use for this kind of functionality somewhere in my code and would rather post a clean example instead of my actual code:
func someTypes() -> [Any.Type] {
var ret = [Any.Type]()
for (var i = 0; i<rand()%10; i++) {
if (rand()%2 == 0){ ret.append(Int.self) }
else {ret.append(String.self) }
}
return ret
}
func test() {
var ts = self.someTypes()
for t in ts {
var arr = Array<t>()
}
}
Swift's static typing means the type of a variable must be known at compile time.
In the context of a generic function func foo<T>() { ... }, T looks like a variable, but its type is actually known at compile time based on where the function is called from. The behavior of Array<T>() depends on T, but this information is known at compile time.
When using protocols, Swift employs dynamic dispatch, so you can write Array<MyProtocol>(), and the array simply stores references to things which implement MyProtocol — so when you get something out of the array, you have access to all functions/variables/typealiases required by MyProtocol.
But if t is actually a variable of kind Any.Type, Array<t>() is meaningless since its type is actually not known at compile time. (Since Array is a generic struct, the compiler needs know which type to use as the generic parameter, but this is not possible.)
I would recommend watching some videos from WWDC this year:
Protocol-Oriented Programming in Swift
Building Better Apps with Value Types in Swift
I found this slide particularly helpful for understanding protocols and dynamic dispatch:
There is a way and it's called generics. You could do something like that.
class func foo() {
test(Int.self)
}
class func test<T>(t: T.Type) {
var arr = Array<T>()
}
You will need to hint the compiler at the type you want to specialize the function with, one way or another. Another way is with return param (discarded in that case):
class func foo() {
let _:Int = test()
}
class func test<T>() -> T {
var arr = Array<T>()
}
And using generics on a class (or struct) you don't need the extra param:
class Whatever<T> {
var array = [T]() // another way to init the array.
}
let we = Whatever<Int>()
jtbandes' answer - that you can't use your current approach because Swift is statically typed - is correct.
However, if you're willing to create a whitelist of allowable types in your array, for example in an enum, you can dynamically initialize different types at runtime.
First, create an enum of allowable types:
enum Types {
case Int
case String
}
Create an Example class. Implement your someTypes() function to use these enum values. (You could easily transform a JSON array of strings into an array of this enum.)
class Example {
func someTypes() -> [Types] {
var ret = [Types]()
for _ in 1...rand()%10 {
if (rand()%2 == 0){ ret.append(.Int) }
else {ret.append(.String) }
}
return ret
}
Now implement your test function, using switch to scope arr for each allowable type:
func test() {
let types = self.someTypes()
for type in types {
switch type {
case .Int:
var arr = [Int]()
arr += [4]
case .String:
var arr = [String]()
arr += ["hi"]
}
}
}
}
As you may know, you could alternatively declare arr as [Any] to mix types (the "heterogenous" case in jtbandes' answer):
var arr = [Any]()
for type in types {
switch type {
case .Int:
arr += [4]
case .String:
arr += ["hi"]
}
}
print(arr)
I would break it down with the things you already learned from the first answer. I took the liberty to refactor some code. Here it is:
func someTypes<T>(t: T.Type) -> [Any.Type] {
var ret = [Any.Type]()
for _ in 0..<rand()%10 {
if (rand()%2 == 0){ ret.append(T.self) }
else {
ret.append(String.self)
}
}
return ret
}
func makeArray<T>(t: T) -> [T] {
return [T]()
}
func test() {
let ts = someTypes(Int.self)
for t in ts {
print(t)
}
}
This is somewhat working but I believe the way of doing this is very unorthodox. Could you use reflection (mirroring) instead?
Its possible so long as you can provide "a hint" to the compiler about the type of... T. So in the example below one must use : String?.
func cast<T>(_ value: Any) -> T? {
return value as? T
}
let inputValue: Any = "this is a test"
let casted: String? = cast(inputValue)
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
Why Swift doesn't just allow us to let casted = cast<String>(inputValue) I'll never know.
One annoying scenerio is when your func has no return value. Then its not always straightford to provide the necessary "hint". Lets look at this example...
func asyncCast<T>(_ value: Any, completion: (T?) -> Void) {
completion(value as? T)
}
The following client code DOES NOT COMPILE. It gives a "Generic parameter 'T' could not be inferred" error.
let inputValue: Any = "this is a test"
asyncCast(inputValue) { casted in
print(casted)
print(type(of: casted))
}
But you can solve this by providing a "hint" to compiler as follows:
asyncCast(inputValue) { (casted: String?) in
print(casted) // Optional("this is a test")
print(type(of: casted)) // Optional<String>
}
In a Swift class, I want to use a property as a default parameter value for a method of the same class.
Here is my code :
class animal {
var niceAnimal:Bool
var numberOfLegs:Int
init(numberOfLegs:Int,animalIsNice:Bool) {
self.numberOfLegs = numberOfLegs
self.niceAnimal = animalIsNice
}
func description(animalIsNice:Bool = niceAnimal,numberOfLegs:Int) {
// I'll write my code here
}
}
The problem is that I can't use my niceAnimal property as a default function value, because it triggers me a compile-time error :
'animal.Type' does not have a member named 'niceAnimal'
Am I doing something wrong ? Or is it impossible in Swift ? If that's impossible, do you know why ?
I don't think you're doing anything wrong.
The language specification only says that a default parameter should come before non-default parameters (p169), and that the default value is defined by an expression (p637).
It does not say what that expression is allowed to reference. It seems like it is not allowed to reference the instance on which you are calling the method, i.e., self, which seems like it would be necessary to reference self.niceAnimal.
As a workaround, you could define the default parameter as an optional with a default value of nil, and then set the actual value with an "if let" that references the member variable in the default case, like so:
class animal {
var niceAnimal: Bool
var numberOfLegs: Int
init(numberOfLegs: Int, animalIsNice: Bool) {
self.numberOfLegs = numberOfLegs
self.niceAnimal = animalIsNice
}
func description(numberOfLegs: Int, animalIsNice: Bool? = nil) {
if let animalIsNice = animalIsNice ?? self.niceAnimal {
// print
}
}
}
I think for now you can only use literals and type properties as default arguments.
The best option would be to overload the method, and you can implement the shorter version by calling the full one. I only used a struct here to omit the initializer.
struct Animal {
var niceAnimal: Bool
var numberOfLegs: Int
func description(#numberOfLegs: Int) {
description(niceAnimal, numberOfLegs: numberOfLegs)
}
func description(animalIsNice: Bool, numberOfLegs: Int) {
// do something
}
}
I'm trying to port the Matrix example from Swift book to be generic.
Here's what I got so far:
struct Matrix<T> {
let rows: Int, columns: Int
var grid: T[]
init(rows: Int, columns: Int, repeatedValue: T) {
self.rows = rows
self.columns = columns
grid = Array(count: rows * columns, repeatedValue: repeatedValue)
}
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> T {
get {
assert(indexIsValidForRow(row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValidForRow(row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
Note that I had to pass repeatedValue: T to the constructor.
In C#, I would have just used default(T) which would be 0 for numbers, false for booleans and null for reference types. I understand that Swift doesn't allow nil on non-optional types but I'm still curious if passing an explicit parameter is the only way, or if I there is some equivalent of default(T) there.
There isn't. Swift forces you to specify the default value, just like then you handle variables and fields. The only case where Swift has a concept of default value is for optional types, where it's nil (Optional.None).
An iffy 'YES'. You can use protocol constraints to specify the requirement that your generic class or function will only work with types that implement the default init function (parameter-less). The ramifications of this will most likely be bad (it doesn't work the way you think it does), but it is the closest thing to what you were asking for, probably closer than the 'NO' answer.
For me I found this personally to be helpful during development of a new generic class, and then eventually I remove the constraint and fix the remaining issues. Requiring only types that can take on a default value will limit the usefulness of your generic data type.
public protocol Defaultable
{
init()
}
struct Matrix<Type: Defaultable>
{
let rows: Int
let columns: Int
var grid: [Type]
init(rows: Int, columns: Int)
{
self.rows = rows
self.columns = columns
grid = Array(count: rows * columns, repeatedValue: Type() )
}
}
There is a way to get the equivalent of default(T) in swift, but it's not free and it has an associated hazard:
public func defaultValue<T>() -> T {
let ptr = UnsafeMutablePointer<T>.alloc(1)
let retval = ptr.memory
ptr.dealloc(1)
return retval;
}
Now this is clearly a hack because we don't know if alloc() initializes to something knowable. Is it all 0's? Stuff left over in the heap? Who knows? Furthermore, what it is today could be something different tomorrow.
In fact, using the return value for anything other than a placeholder is dangerous. Let's say that you have code like this:
public class Foo { /* implementation */
public struct Bar { public var x:Foo }
var t = defaultValue<Bar>();
t = someFactoryThatReturnsBar(); // here's our problem
At the problem line, Swift thinks that t has been initialized because that's what Swift's semantics say: you cannot have a variable of a value type that is uninitialized. Except that it is because default<T> breaks those semantics. When you do the assignment, Swift emits a call into the value witness table to destroy the existing type. This will include code that will call release on the field x, because Swift semantics say that instances of objects are never nil. And then you get a runtime crash.
However, I had cause to interoperate with Swift from another language and I had to pass in an optional type. Unfortunately, Swift doesn't provide me with a way to construct an optional at runtime because of reasons (at least I haven't found a way), and I can't easily mock one because optionals are implemented in terms of a generic enum and enums use a poorly documented 5 strategy implementation to pack the payload of an enum.
I worked around this by passing a tuple that I'm going to call a Medusa tuple just for grins: (value: T, present: Bool) which has the contract that if present is true, then value is guaranteed to be valid, invalid otherwise. I can use this safely now to interop:
public func toOptional<T>(optTuple: (value:T, present:Bool)) -> T?
{
if optTuple.present { return optTuple.value }
else { return nil }
}
public func fromOptional<T>(opt: T?) -> (T, Bool)
{
if opt != nil { return (opt!, true) }
else {
return (defaultValue(), false)
}
}
In this way, my calling code passes in a tuple instead of an optional and the receiving code and turn it into an optional (and the reverse).
In fact, generic types can have optional values.
You can do it with protocols
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let someType = SomeType<String>()
let someTypeWithDefaultGeneric = SomeType()
}
}
protocol Default {
init()
}
extension Default where Self: SomeType<Void> {
init() {
self.init()
}
}
class SomeType<T>: Default {
required init() {}
}