Editing protocol options

I see types like TCP or TLS include methods to change an option. These methods return Self.

I want something similar for my protocol framer. Like the types above, the user-level object is a value type. The inards to work with Apple's code is a Framer<MyImplementation> property.

I don't know from looking at the method descriptions if the returned Self is a copy/reference of the receiver, with the particular option mutated, or a clone with an independent option value.

I tried the clone approach. I would copy the external value type, but the new values would contain a mutated clone of the internal reference type. But NWProtocolFramer.Options doesn't seem to have a clone initializer, and it doesn't conform to NSObjectProtocol, so I have to go with the copy/reference approach.

So, I would return self, but mutate the internal Framer instance's Options dictionary first? Are there any subtlies to mutating the internal Options' property dictionary?

Answered by DTS Engineer in 913938022

I would solve this problem by using a struct to record your options in its own properties and then, as a final step, have a method that creates a new NWProtocolFramer.Options value from those properties. In most cases this would only get called once, at the end of the process, solely so you can apply the options to the protocol stack.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I would solve this problem by using a struct to record your options in its own properties and then, as a final step, have a method that creates a new NWProtocolFramer.Options value from those properties. In most cases this would only get called once, at the end of the process, solely so you can apply the options to the protocol stack.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

So...

  • Add a non-public initializer to copy-by-reference the Framer<MyImplementation> object.
  • When an option-mutating method is called, update the internal by-value cache, then create a corresponding NWProtocolFramer.Options object, then change the Framer object to replace its current Options.

This should work as long as the intermediate wrapper objects aren't actually used, since all of those wrappers point to the same framer. As you said, this should work; fixing the flaw would be "planning for Machiveli instead of Murphy".

Hmmm, either I’ve completely misinterpreted your outline or you’ve missed my point. Let me elaborate on my suggestion…

Let’s say I have a waffle framer that has two options:

  • Extra toasty
  • Gloss finish

I represent like so:

struct WaffleOptions {
    var makeExtraToasty: Bool = false
    var applyGlossFinish: Bool = false
}

I then add modifiers like this:

extension WaffleOptions {

    func extraToasty() -> Self {
        var r = self
        r.makeExtraToasty = true
        return r
    }

    func glossFinish() -> Self {
        var r = self
        r.applyGlossFinish = true
        return r
    }
}

and use them in a fluent style like so:

let o = WaffleOptions()
    .extraToasty()
    .glossFinish()

Finally, when it comes to interfacing with Network framework, I add a method that creates the framer options:

extension WaffleOptions {

    func framerOption() -> NWProtocolFramer.Options {
        let r = NWProtocolFramer.Options(definition: WaffleFramer.definition)
        r["make-extra-toasty"] = self.makeExtraToasty
        r["apply-gloss-finish"] = self.applyGlossFinish
        return r
    }
}

and then add that to the end of the chain when setting up the parameters:

let params: NWParameters = …
params.defaultProtocolStack.applicationProtocols = [
    WaffleOptions()
        .extraToasty()
        .glossFinish()
        .framerOption()
]

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"