jay492355
jay492355

Reputation: 594

Using generic arrays in swift

This should be pretty simple. I have a data source that always gives me UInt16s. I derive different data sets from this raw data and plot the results. Some of the derived data sets are Floats, some are UInt8s, and some are UInt16s.

I queue the derived data where it is later retrieved by my graphing classes.

Queues are arrays of arrays and look like this: [[UInt16]], [[Float]], or [[UInt8]].

I'm trying to make use of generics, but I get a compiler error when I try to append a generic-typed array to an array that is declared to be [[AnyObject]].

As I'm learning Swift, I keep bumping into this AnyObject / generic problem quite a bit. Any help/insight is appreciated.

class Base: NSObject {

   var queue : [[AnyObject]] = Array()

   func addtoQueue<T>(dataSet: [T]) {
      queue.append(dataSet)
   }

   func removeFromQueue() -> [AnyObject]? {
      return queue.removeAtIndex(0)
   }
}

class DataSet1 : Base {

   func getSomeData(rawData: [UInt16]) {
      var result : [Float] = processRawData(rawData)
      addToQueue(result)
   }
}

Upvotes: 2

Views: 219

Answers (2)

matt
matt

Reputation: 535201

It may be that you don't understand what AnyObject is. It is the protocol type automatically adopted by all classes. But Float, UInt16, and UInt8 are not classes; they are structs.

It may be that you meant [[Any]] as the type of your array. In that case, you don't need a generic. This works:

var queue : [[Any]] = Array()
func addToQueue(dataSet:[Any]) {
    queue.append(dataSet)
}
let f = Float(1)
let i1 = UInt8(2)
let i2 = UInt16(3)
addToQueue([f])
addToQueue([i1])
addToQueue([i2])

If you insist on [[AnyObject]], you have two problems:

Your generic is too generic. Not everything in the universe is an AnyObject, so how can the compiler know that this thing will be an AnyObject? Write your generic like this:

func addToQueue<T:AnyObject>(dataSet:[T]) {
    queue.append(dataSet)
}

Now the compiler knows that only something conforming to AnyObject will be used when calling this method. At that point, however, it is a little hard to see what your generic is for; you are not using T elsewhere, so just write a normal function:

func addToQueue(dataSet:[AnyObject]) {
    queue.append(dataSet)
}

The second problem is that you will still have to convert (as Drew's answer tells you), because there is no automagic bridging between, say, a UIInt16 and an AnyObject. Float is _ObjectiveCBridgeable, but UInt16 and UInt8 are not.

var queue : [[AnyObject]] = Array()
func addToQueue(dataSet:[AnyObject]) {
    queue.append(dataSet)
}
let f = Float(1)
let i1 = UInt8(2)
let i2 = UInt16(3)
addToQueue([f])
addToQueue([NSNumber(unsignedChar: i1)])
addToQueue([NSNumber(unsignedShort: i2)])

Upvotes: 2

Drew Beaupre
Drew Beaupre

Reputation: 2447

What you'll need to do is 'box' up the underlying value. You could accomplish this using a protocol which exposed a setter/getter and an enum property of the underlying type that you can 'switch' on. Alternatively, you could see if you can make Foundation's built in NSNumber work for you. It's doing exactly that: boxes up any number of numerical types for you to store and retrieve later on:

var queue : Array<NSNumber> = []

queue.append(NSNumber(int: 1))
queue.append(NSNumber(double: 2.5))
queue.append(NSNumber(float: 3.5))

var types : Array<String> = []

for item in queue{

    println("number type: \(item)")
}

Upvotes: 1

Related Questions