1

This is the case:

public enum NodeFeature: UInt16 {
    case relay      = 0x01
    case proxy      = 0x02
    case friend     = 0x04
    case lpn        = 0x08
}

public struct NodeFeatures {
    public let rawValue: UInt16

    public init(rawValue: UInt16) {
        self.rawValue = rawValue
    }

    public init(features: NodeFeature...) {
        var rawValue = UInt16(0)
        for feature in features {
            rawValue |= feature.rawValue
        }
        self.rawValue = rawValue
    }

    public func hasFeature(_ feature: NodeFeature) -> Bool {
        return rawValue & feature.rawValue > 0
    }
}

And this is a response from server:

"feature": {
  "relay": true,
  "proxy": false,
  "friend": false,
  "lowPower": false
}

Now I need to create an instance of NodeFeatures with only true values:

var features = [NodeFeature]() // how to declare and prepare the list of args?

if true {
    features.append(.first)
} else if true {
    features.append(.third)
}

let wrapper = NodeFeatures(features: features) //... to pass it as a variable to the initializer.

But the error is following:

Cannot convert value of type '[NodeFeature]' to expected argument type 'NodeFeatures'

10
  • try to change init(features: Feature...) to init(features: [Feature]).You are initializing multiple enum cases instead of single. Commented Jun 26, 2017 at 10:38
  • No, it is not the case, I need to prepare it from the other side:) The argument in initializer is from SDK... Commented Jun 26, 2017 at 10:39
  • Can you give more info?What you are doing exactly with init() part.The error is clear argument type mismatch. Commented Jun 26, 2017 at 10:43
  • Feature and FeatureWrapper is from SDK. I CANNOT change it. But I need to pass there a list of Features. The list depends on response from server:) Do you understand? Commented Jun 26, 2017 at 10:46
  • 1
    @BartłomiejSemańczyk: This won't help because you did not write the SDK, but an OptionSet would be a better suited type to represent both single features and a set of features. Commented Jun 26, 2017 at 11:08

1 Answer 1

2

You cannot pass an array to a function taking a variadic argument, or dynamically "build" a variadic argument list, compare e.g. Passing an array to a function with variable number of args in Swift.

But fortunately, the type has another initializer

public init(rawValue: UInt16)

which you can use in different ways.

Option 1: Use an integer bit mask to assemble the features instead of an array:

var rawFeatures = UInt16(0)
if condition {
    rawFeatures |= NodeFeature.relay.rawValue
} else if condition {
    rawFeatures |= NodeFeature.proxy.rawValue
}
let wrapper = NodeFeatures(rawValue: rawFeatures)

Option 2: Keep your array, but compute the combined raw value to create the NodeFeatures value:

var features = [NodeFeature]()
if condition {
    features.append(.relay)
} else if condition {
    features.append(.proxy)
}

let rawFeatures = features.reduce(0, { $0 | $1.rawValue })
let wrapper = NodeFeatures(rawValue: rawFeatures)

Option 3: Define another initializer taking an array argument in an extension:

extension NodeFeatures {

    public init(features: [NodeFeature]) {
        let rawValue = features.reduce(0, { $0 | $1.rawValue })
        self.init(rawValue: rawValue)
    }
}

Now you can pass your array directly:

var features = [NodeFeature]()
if condition {
    features.append(.relay)
} else if condition {
    features.append(.proxy)
}
let wrapper = NodeFeatures(features: features)
Sign up to request clarification or add additional context in comments.

2 Comments

Be careful to keep your init routine in sync with the SDK's init when you update the SDK. They might change what init does.
Thank you, you are always very helpful:)

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.