Как получить доступ к свойствам внутреннего объекта из суперкласса без шаблона - PullRequest
0 голосов
/ 27 июня 2019

Есть ли способ создать методы доступа к свойствам внутреннего объекта без использования шаблона?

Вот пример класса с образцом

public class Foo {
    internal let bar: Bar

    internal init(bar: Bar) {
        self.bar = bar
    }

    private struct Bar: Codable {
        let id: Int
        let name: String
    }  

    // MARK: - Boilerplate 

    public var id: Int { 
        return self.bar.id
    }

    public var name: String { 
        return self.bar.name
    }
}

// Usage

do {
    let bar: Bar = try data.decoded() 
    let foo = Foo(bar: bar)

    print(foo.id)
    print(foo.name)
} catch {
    ...
}

Есть ли способ сделать это без необходимости писать шаблон? Для более крупных объектов с большим количеством свойств это может быть очень полезно

Обратите внимание: модификаторы контроля доступа важны

1 Ответ

2 голосов
/ 27 июня 2019

Новое в Swift 5.1, вы можете использовать динамический поиск членов с ключевым путем.Это прекрасно работает для такого рода ситуации, когда ключевые пути поддерживают полную проверку типов.Вот упрощенный пример (без попытки отразить вашу реальную ситуацию):

struct Dog {
    let name : String
}
@dynamicMemberLookup
struct Kennel {
    let dog : Dog
    subscript(dynamicMember kp:KeyPath<Dog,String>) -> String {
        self.dog[keyPath:kp]
    }
}

В результате получается, что с учетом питомника k мы можем получить k.name как способ получения k.dog.name.

Но говорить k.xxx было бы незаконно, потому что у Собаки нет свойства String xxx;это то, что я имею в виду, когда говорю, что поддерживается полная проверка типов.


Старый способ - использовать протоколы.Таким образом, вы можете использовать расширение протокола для ввода шаблона.

protocol HasNameAndId {
    var id: Int {get}
    var name: String {get}
}

protocol WrapperOfHasNameAndId {
    associatedtype T : HasNameAndId
    var bar: T {get}
}

extension WrapperOfHasNameAndId { // boilerplate
    var id: Int {
        return self.bar.id
    }
    var name: String {
        return self.bar.name
    }
}

// ==============

struct Bar: HasNameAndId {
    let id: Int
    let name: String
}

class Foo : WrapperOfHasNameAndId {
    let bar: Bar
    init(bar: Bar) {
        self.bar = bar
    }
}

// =======

let f = Foo(bar: Bar(id: 1, name: "howdy"))
print(f.id) // 1
print(f.name) // "howdy"
...