0

I have a struct called trip.

struct trip {
    var name: String
    var description: String
    var elements: [Any] = []

    mutating func addItemToElements(newValue: Any) {
       elements.append(newValue)
    }
}

As you can see, there is an array inside. I'm adding some other structs like element_flight into this array by function addItemtoElements.

struct element_flight {
    var origin: String
    var destination: String
    var flightno: String
    var departure: NSDate
    var arrival: NSDate
    var seat: String
}

Then I'm trying to create a list using table view:

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "elementTrip", for: indexPath) as! CellInElementsOfTripsTableViewCell
    let elem = trips[0].elements[indexPath.row]
    cell.mainTextLabel.text = elem.origin //it doesn't work

    return cell
}

I can't get any of parts of struct (like origin in code). What am I doing wrong?

I'm creating similar structs to element_flight and it could be the best way to put it in one array and then show in table view.

1
  • Try cast them to the correct type OR store what type they are and cast them correctly to the concrete type. Right now, all the compiler knows is that elem is of type Any on line: let elem = trips[0].elements[indexPath.row]. Commented Jul 17, 2016 at 0:29

3 Answers 3

6

A simple, naive solution would be to cast elem to the correct type:

cell.mainTextLabel.text = (elem as! element_flight).origin

However, since the elements array can store Any, what if elem is some other type? Obviously, it will crash!

I don't understand why you want to store a bunch of Any in elements. This is a sign or bad code. Any is seldom used in Swift.

If you're just going to store some types, but not Any types, in elements, create a protocol and make all the types that you want to store conform to it. At least you get a little bit of type safety.

Let's say your array will only contain two structs: element_flight and SomeOtherStruct. You should do something like this:

protocol SomeProtocol { // please give this a proper name yourself
    // properties/methods that are common among element_flight and SomOtherStruct
}

struct element_flight: SomeProtocol {
    // ...
}

struct SomeOtherStruct: SomeProtocol {
    // ...
}

And change the array to be of type [SomeProtocol].

Now in the cellForRowAtIndexPath method, you need to test whether elem is element_flight or SomeOtherStruct:

if let flight = elem as? element_flight {
    cell.mainTextLabel.text = flight.origin
} else if let someOtherStuff = elem as? SomeOtherStruct {
    // do some other stuff
} else {
    // something's wrong if this is executed, maybe call fatalError
}
Sign up to request clarification or add additional context in comments.

1 Comment

It was extremely helpful, now it works like a charm. Thanks!
0

You should cast them to FlightInfo (use this name instead of element_flight - type name in Swift should be written in CamelCase).

override func tableView(_ tableView: UITableView, 
           cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  let cell = tableView.dequeueReusableCell(withIdentifier: "elementTrip", 
                     for: indexPath) as! CellInElementsOfTripsTableViewCell

  if let flightInfo = trips[0].elements[indexPath.row] as? FlightInfo {
    cell.mainTextLabel.text = flightInfo.origin //it doesn't work
  }

  return cell
}

1 Comment

Actually, FlightInfo is in PascalCase.
0

A another approach would be to store the different structs in an Any array and use the is variable to test the type before copying it into a variable.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.