1

I have a couple of different types of structs (Promo & Event). I'd like to create an empty array which gets populated with an array of each type depending on the outcome of an if statement.

So something like this:

var dataArray:[Any] = []  // see options I've tried below 

if myTest == true {
    dataArray = [Promo, Promo, Promo]
} else {
    dataArray = [Event, Event, Event]    
}

I have tried using:

1. var dataArray: [Any] = []
2. var dataArray: [AnyObject] = []
3. var dataArray: [Any] = [Any]()
4. var dataArray: [AnyObject] = [AnyObject]()

but when I try to store an array of Promo Structs in dataArray I get an error Cannot assign value of type '[Promo]' to type '[Any]' etc.

So, how do I initialise an array so that it can store a variety of (unknown) Structs. Or how do I modify my Structs to enable them to be stored in an array?

I'm really struggling to see what I'm doing wrong so any pointers would be v. helpful.


Here are my Structs: Promo.swift

import Foundation

struct Promo {

    // initialise the stored properties for use later
    let promoId : Int
    let date : NSDate
    let title: String
    let body: String
    let busName : String
    let busId : Int
    let categoryId: Int
    let featured: Bool

    // a universal init() method which has optional parameters
    init(promoId: Int,
         date: NSDate,
         title: String,
         body: String,
         busName: String,
         busId: Int,
         categoryId: Int,
         featured: Bool
        ){
        self.promoId = promoId
        self.date = date
        self.title = title
        self.body = body
        self.busName = busName
        self.busId = busId
        self.categoryId = categoryId
        self.featured = featured
    }
}

// allow us to compare structs
extension Promo: Equatable {}
func ==(lhs: Promo, rhs: Promo) -> Bool {
    return lhs.promoId == rhs.promoId
        && lhs.date == rhs.date
        && lhs.title == rhs.title
        && lhs.body == rhs.body
        && lhs.busName == rhs.busName
        && lhs.busId == rhs.busId
        && lhs.categoryId == rhs.categoryId
        && lhs.featured == rhs.featured
}

Event.swift

import Foundation

struct Event {

    // initialise the stored properties for use later
    let eventId : Int
    let date : NSDate
    let title: String
    let body: String
    let busName : String
    let busId : Int
    let categoryId: Int

    // a universal init() method which has optional parameters
    init(eventId: Int,
         date: NSDate,
         title: String,
         body: String,
         busName: String,
         busId: Int,
         categoryId: Int
        ){
        self.eventId = eventId
        self.date = date
        self.title = title
        self.body = body
        self.busName = busName
        self.busId = busId
        self.categoryId = categoryId
    }
}
James
  • 1,292
  • 1
  • 14
  • 29
  • In the example you're not assigning the structs to dataArray, rather the type. Did you mean to use dataArray = [Promo(), Promo(), Promo()], etc instead? – Casey Fleser Jun 20 '16 at 14:42
  • Yes, @CaseyFleser that's actually what's assigned (I get an array of Promo structs returned from a function). Thanks – James Jun 20 '16 at 14:55
  • Possible duplicate of [Why isn't \[SomeStruct\] convertible to \[Any\]?](http://stackoverflow.com/questions/37188580/why-isnt-somestruct-convertible-to-any) – Hamish Jun 20 '16 at 15:11

2 Answers2

2

This may not be exactly what you intended, but you can make this a bit cleaner by using classes instead of structs. It appears that a 'Promo' is just an 'Event' with one extra data member (featured)... If that's the case, then you can rename the Promo.promoId field Promo.eventId, and then make it a subclass of Event. Like this:

class Promo : Event {
    let featured: Bool

    // a universal init() method which has optional parameters
    init(eventId: Int,
         date: NSDate,
         title: String,
         body: String,
         busName: String,
         busId: Int,
         categoryId: Int,
         featured: Bool
        ){
        self.featured = featured
        super.init(eventId: eventId, date: date, title: title, body: body, busName: busName, busId: busId, categoryId: categoryId)
    }
}

Then just create the data array like this:

var dataArray = [Event]()

if myTest == true {
    dataArray = [promo1, promo2, promo3]
} else {
    dataArray = [event1, event2, event3]
}

To use the featured member for a Promo you'll still need to cast like this:

if let thisPromo = dataArray[0] as? Promo {
    print(thisPromo.featured)
}
  • Thanks @Steve - I did wonder about that but this is a simplified version for SO. There are actually 4 structs with pretty different members (I just copied Events & Promos as they're the shortest :-) I like your idea though and am always keen to simplify things so will give it some thought. – James Jun 20 '16 at 15:03
1

If you are trying to assign to dataArray from [Promo] or [Event] arrays, you could map:

var dataArray:[Any] = []
var promoArray:[Promo] = [Promo(), Promo(), Promo()]
var eventArray:[Event] = [Event(), Event(),Event()]

if myTest == true {
    dataArray = promoArray.map { $0 as Any }
} else {
    dataArray = eventArray.map { $0 as Any }
}

Or create new Any arrays:

if myTest == true {
    dataArray = Array<Any>(arrayLiteral: promoArray)
} else {
    dataArray = Array<Any>(arrayLiteral: eventArray)
}
Casey Fleser
  • 5,707
  • 1
  • 32
  • 43