Using a protocol with typealias as a property

I have a protocol with typealias:

protocol Archivable {
    typealias DataType

    func save(data: DataType, withNewName newName: String) throws
    func load(fromFileName fileName: String) throws -> DataType
}

and the class corresponding to this protocol:

class Archiver: Archivable {
    typealias DataType = Int

    func save(data: DataType, withNewName newName: String) throws {
        //saving
    }

    func load(fromFileName fileName: String) throws -> DataType {
        //loading
    }
}

and I would like to use Archivableas a property in another class, for example:

class TestClass {

    let arciver: Archivable = Archiver() //error here: Protocol 'Archivable' can only be used as a generic constraint because it has Self or associated type requiments
}

but with an error

The Archived protocol can only be used as a general restriction, since it has its own or related requests such as

My goal is that I TestClassshould only see Archiverhow Archiveable, so if I want to change the save / load mechanism, I just need to create a new class that matches Archivableas set as property in TestClass, but I don't know if this is possible, and if yes, how.

And I would like to avoid using AnyObjectinstead of DataType.

+4
3

, , . R Menke, , , . TestClass , , DataType . Archivable :

class AnyArchiver<T>: Archivable {
    private let _save: ((T, String) throws -> Void)
    private let _load: (String throws -> T)

    init<U: Archivable where U.DataType == T>(_ archiver: U) {
        _save = archiver.save
        _load = archiver.load
    }

    func save(data: T, withNewName newName: String) throws {
        try _save(data, newName)
    }

    func load(fromFileName fileName: String) throws -> T {
        return try _load(fileName)
    }
}

Swift AnySequence, Archiver TestClass :

class TestClass {
    let archiver = AnyArchiver(Archiver())
}

Swift TestClass ', AnyArchiver<Int>. , , , , DataType StringArchiver, ArrayArchiver, IntArchiver .. :

let intArchiver: AnyArchiver<Int>
let stringArchiver: AnyArchiver<String>
let modelArchiver: AnyArchiver<Model>

:

protocol IntArchivable: Archivable {
    func save(data: Int, withNewName newName: String) throws
    func load(fromFileName fileName: String) throws -> Int
}
protocol StringArchivable: Archivable {
    func save(data: String, withNewName newName: String) throws
    func load(fromFileName fileName: String) throws -> String
}
protocol ModelArchivable: Archivable {
    func save(data: Model, withNewName newName: String) throws
    func load(fromFileName fileName: String) throws -> Model
}

let intArchiver: IntArchivable
let stringArchiver: StringArchivable
let modelArchiver: ModelArchivable

, - . , !

+3

archiver:

let archiver: Archivable = Archiver()

. Archivable , .

" (Swift 2)":

( ) , . , , .

, , Archivable :

protocol IntArchivable: Archivable {
    func save(data: Int, withNewName newName: String) throws

    func load(fromFileName fileName: String) throws -> Int
}

:

class Archiver: IntArchivable {
    func save(data: Int, withNewName newName: String) throws {
        //saving
    }

    func load(fromFileName fileName: String) throws -> Int {
        //loading
    }
}

Swift , archiver :

let archiver: Archivable<Int> = Archiver()

, , , .

" (Swift 2)":

, , .

, , archiver Archivable<Int>, , , , archiver, , , .. , , archiver , , .

TestClass , Archivable :

class TestClass<T, A: Archivable where A.DataType == T> {
    private let archivable: A

    init(archivable: A) {
        self.archivable = archivable
    }

    func test(data: T) {
        try? archivable.save(data, withNewName: "Hello")
    }
}

, Archivable :

class TestClass {        
    func test<T, A: Archivable where A.DataType == T>(data: T, archivable: A) {
        try? archivable.save(data, withNewName: "Hello")
    }
}
+1

Hector gives a more complex, although ultimately the best solution is higher, but I thought that I would send an alternative answer anyway. This is simpler, but probably less flexible in the long run.

typealias DataType = Int

protocol Archivable {
    var data: DataType { get set }

    func save(data: DataType, withNewName newName: String) throws
    func load(fromFileName fileName: String) throws -> DataType
}

class Archiver: Archivable {
    var data:DataType = 0

    func save(data: DataType, withNewName newName: String) throws {
        //saving
    }

    func load(fromFileName fileName: String) throws -> DataType {
        return data
    }
}

class TestClass {
    let arciver: Archivable = Archiver()
}
0
source

Source: https://habr.com/ru/post/1618795/


All Articles