2

I am trying to create an array of multiple structs, I have created a protocol to do so that allows me to get and set similar properties but not when properties are different. My current code right now is below:

structs:

struct A: Pr {
poll: String
res: Int
}

struct B: Pr {
poll:String
ont: String
}

Protocol:

protocol Pr {
   var poll:String { get set }
}

var type without initialization:

var field:[Pr]
11
  • 1
    What is the problem with your code? Commented Apr 7, 2021 at 17:09
  • Say, you had an array of different types with different properties - what's next? How are you going to use it? Commented Apr 7, 2021 at 17:13
  • @NickKim my code does not allow me to get or set individual props of the structs which are res and ont respectively Commented Apr 7, 2021 at 17:15
  • @NewDev i want to be able to get or set them on a for loop Commented Apr 7, 2021 at 17:16
  • i can only get and set poll in this case Commented Apr 7, 2021 at 17:16

2 Answers 2

3

After sanitizing your code a bit:

protocol Pr {
   var poll:String { get set }
}

struct A: Pr {
  var poll: String
  var res: Int
}

struct B: Pr {
  var poll:String
  var ont: String
}

var field: [Pr]

If I understand what you want is something like this:

// Just an example to fill array with something for a demo:
let a = A(poll: "pollA", res: 1)
let b = B(poll: "pollB", ont: "ont")

field = [Pr]()
field.append(a)
field.append(b)

// The actual solution
for pr in field {

    print(pr.poll)

    switch pr {
    case let pr as A:
        print(pr.res)
    case let pr as B:
        print(pr.ont)
    default:
        print("no more properties")
    }
}

That is: you can cast each item in array as given type to get properties specific to the type. This solves the GET problem. Set is more complicated, since you have an array and structs, which is copied when modified. So technically you can change them, but it won't be the same instance. The most simple way to resolve this, is to have a function that returns an array of modified [Pr] objects, which you can assign back to field:

func modify() -> [Pr] {

    var result = [Pr]()

    for pr in field {

        switch pr {
        case let pr as A:
            let a = A(poll: pr.poll + "changed", res: pr.res + 1)
            result.append(a)
        case let pr as B:
            let b = B(poll: pr.poll + "changed", ont: pr.ont + "changed")
            result.append(b)
        default:
            print("skip")
        }
    }

    return result
}

field = modify()

But this may not be a good solution if you are dealing with tons of data, lots of copies, etc, etc... So a more specific use case would be needed to make the answer more useful.

Sign up to request clarification or add additional context in comments.

1 Comment

This is the closest to a solution but as you said it isn't a good solution with tons of data and dynamic changes, thumbs up thought 👍
1

You have two problems:

  1. An array of structs that conform to the Pr protocol is not an array of A and B objects:

  2. The Array and Struct types are both value types, so you can't cast an entry from your array to a specific concrete type without making a copy.

This code solves problem 1, but not problem 2:

(field[0] as? A)?.res = 5

I'm not sure if there is a solution to your problem, other than converting your A and B to class (reference type) objects. This code works:

protocol Pr {
   var poll:String { get set }
}

class A: Pr, CustomStringConvertible {
    var poll: String
    var res: Int
    
    init(poll: String, res: Int) {
        self.poll = poll
        self.res = res
    }
    
    var description: String {
        return ("A(poll: \(poll), res:\(res))")
    }
}

class B: Pr, CustomStringConvertible {
    var poll:String
    var ont: String

    init(poll: String, ont: String) {
        self.poll = poll
        self.ont = ont
    }
    var description: String {
        return ("B(poll: \(poll), ont:\(ont))")
    }
}

var field:[Pr] = [A(poll:"h", res:3), B(poll:"c", ont:"o"),]
field[0].poll = "p"
field[1].poll = "q"

(field[0] as? A)?.res = 5

(field[1] as? B)?.ont = "z"

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.