Расширение модели класса для универсального типа Swift - PullRequest
1 голос
/ 20 сентября 2019

Я передаю ответ API с Мойей и получаю это значение.Я могу получить объект, но я расширил базовый ответ для обработки дополнительных параметров, но расширенное значение, похоже, не работает.Ожидаемые данные могут быть массивом объектов и просто обычным объектом.После передачи этих значений он перестал работать, и данные не были получены, но передаются все остальные параметры, такие как status, message, кроме data.Вот мой базовый ответ и как я его использовал

class MaxResponseBase: Codable {
    var status: String?
    var message: String?
    var pagination: Pagination?

    var isSucessful: Bool {
        return status == "success"
    }

    struct ErrorMessage {
        static let passwordInvalid = " Current password is invalid."
        static let loginErrorIncorrectInfo = " Incorrect username/password."
        static let loginErrorAccountNotExist = " Invalid request"
    }
}

class MaxResponse<T: Codable>: MaxResponseBase {
    var data: T?
}

class MaxArrayResponse<T: Codable>: MaxResponseBase {
    var data = [T]()
}

Вот мой API-вызов для входа, например

func signin(email: String, password: String) -> Observable<MaxResponse<AuthResponse>> {
        return provider.rx.request(.signin(username: email, password: password))
            .filterSuccess()
            .mapObject(MaxResponse<AuthResponse>.self)
            .asObservable()
    }

как я могу настроить это, чтобы получить объект данных также

JSON

{
  "status" : "success",
  "data" : {
    "is_locked" : false,
    "__v" : 0,
    "created_at" : "2019-04-15T11:57:12.551Z"
  }
}

Это также может быть массив данных

1 Ответ

1 голос
/ 21 сентября 2019

(Примечание: весь приведенный ниже код можно поместить на игровую площадку, чтобы показать, что он работает.)

Чтобы решить эту проблему, вы должны вручную написать все свои инициализаторы.Я разместил код, который делает большую часть этого ниже, но я настоятельно рекомендую использовать структуры вместо классов.Лучше во всех отношениях, если вы используете структуры и ограничения вместо классов и наследования.

struct Pagination: Codable { }

struct AuthResponse: Codable {
    let isLocked: Bool
    let __v: Int
    let createdAt: Date
}

class MaxResponseBase: Codable {
    let status: String?
    let message: String?
    let pagination: Pagination?

    var isSucessful: Bool {
        return status == "success"
    }

    struct ErrorMessage {
        static let passwordInvalid = " Current password is invalid."
        static let loginErrorIncorrectInfo = " Incorrect username/password."
        static let loginErrorAccountNotExist = " Invalid request"
    }

    enum CodingKeys: String, CodingKey {
        case status, message, pagination
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        status = try container.decode(String?.self, forKey: .status)
        message = try? container.decode(String?.self, forKey: .message) ?? nil
        pagination = try? container.decode(Pagination?.self, forKey: .pagination) ?? nil
    }
}

class MaxResponse<T: Codable>: MaxResponseBase {
    let data: T?

    enum DataCodingKeys: String, CodingKey {
        case data
    }

    required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: DataCodingKeys.self)
        data = try container.decode(T?.self, forKey: .data)
        try super.init(from: decoder)
    }
}

let json = """
{
"status" : "success",
"data" : {
"is_locked" : false,
"__v" : 0,
"created_at" : "2019-04-15T11:57:12.551Z"
}
}
"""

let data = json.data(using: .utf8)!

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd'T'HH:mm:ss.SSZ"
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let response = try decoder.decode(MaxResponse<AuthResponse>.self, from: data)

print(response)

Это просто гораздо проще и меньше кода просто использовать структуру:

struct AuthResponse: Codable {
    struct ResponseData: Codable {
        let isLocked: Bool
        let __v: Int
        let createdAt: Date
    }
    let status: String?
    let data: ResponseData
}

let json = """
{
"status" : "success",
"data" : {
"is_locked" : false,
"__v" : 0,
"created_at" : "2019-04-15T11:57:12.551Z"
}
}
"""

let data = json.data(using: .utf8)!

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "YYYY-MM-dd'T'HH:mm:ss.SSZ"
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let response = try decoder.decode(AuthResponse.self, from: data)

print(response)

И если вам действительно нужен тип MaxResponse, тогда сделайтеэто протокол и ваши другие типы соответствуют ему.Я почти готов поспорить, что вам это не нужно.


В ответ на ваши комментарии, вот общее решение с использованием структур:

struct LoginResponseData: Codable {
    let isLocked: Bool
    let __v: Int
    let createdAt: Date
}

struct BlogResponseData: Codable {
    let xxx: Bool
    let yyy: Int
    let createdAt: Date
}

struct BaseRresponse<ResponseData: Codable>: Codable {
    let status: String?
    let data: ResponseData
}
...