简体   繁体   中英

Can we reuse struct on Swift? Or is there any other way?

So I have a user JSON structure that goes like this:

- results: {
    meta: {}
    users: []
  },
- status:

I want to get the user so the User model I implement to get the JSON is like this:

struct Response: Decodable {

    let results: Result
    let status: Int
}

struct Result: Decodable {

    let meta: Meta
    let users: [User]
}

struct Meta: Decodable {

    let total_data: Int
    let total_page: Int
}

struct User: Decodable {

    let avatar_url: String
    let created_at: String
    let updated_at: String
    let email: String
    let id: Int
    let name: String
    let username: String
}

It is working, but when I have another JSON that the structure is similar, let say like this

- results: {
        meta: {}
        rooms: []
      },
    - status:

And when I create Room model, with another struct Response on it, it will cause error because it is duplicated declaration.

Is it possible to reuse struct in Swift? Or is there any convenient way to do this?

Thanks

You could use generics.

struct Response<T: Decodable>: Decodable {
    let results: Result<T>
    let status: Int
}

struct Result<T: Decodable>: Decodable {
    let meta: Meta
    let objects: [T]
}

struct Meta: Decodable {    
    let total_data: Int
    let total_page: Int
}

struct User: Decodable {
    let avatar_url: String
    let created_at: String
    let updated_at: String
    let email: String
    let id: Int
    let name: String
    let username: String
}

let userResponse: Response<User>?

You can try to use generics in the following way:

struct Response<ResultType> : Decodable where ResultType : Decodable {
    let results: ResultType
    let status: Int
}

and then use that struct via:

struct Result: Decodable {
    let something: String
}

let decoder = JSONDecoder()
let data = "{\"status\":123,\"results\":{\"something\":\"hi\"}}".data(using: .utf8)!
let value = try! decoder.decode(Response<Result>.self, from: data) // will be of type Response<Result>

You have one option is to reuse Meta and Status If you use sm

For user You can replace name

struct UserResult: Decodable {

    let meta: Meta
    let users: [User]
}

struct UserResponse: Decodable {

    let results: UserResult
    let status: Int
}

and for Room

struct RoomResult: Decodable {

    let meta: Meta
    let users: [Room]
}

struct RoomResponse: Decodable {

    let results: RoomResult
    let status: Int
}

Depending on your needs, you can use generics to compose the whole struct.

Start with your data models

struct User: Decodable {
    let avatar_url: String
    let created_at: String
    let updated_at: String
    let email: String
    let id: Int
    let name: String
    let username: String
}

struct Room: Decodable {
    let id: Int
    let name: String
}

The goal is to get nice composed types.

typealias UserResponse = Response<Result<User, Meta>>
typealias RoomResponse = Response<Result<Room, Meta>>

The generics types to build from

struct Response<ResultType: Decodable>: Decodable {
    let results: ResultType
    let status: Int
}

struct Result<ItemType: Decodable, MetaType: Decodable>: Decodable {
    let meta: MetaType
    let items: [ItemType]
}

Even Meta is a separate part of the composition.

struct Meta: Decodable {
    let total_data: Int
    let total_page: Int
}

Now lets say we need a custom Meta for the Room response

struct PagedMeta: Decodable {
    let current_page: Int
    let page_count: Int
}

Here is the new type

typealias RoomPagedResponse = Response<Result<Room, PagedMeta>>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM