我正在尝试使用Generics
编写网络管理员。而且我没有这样做。下面是我的代码和错误屏幕截图。 BaseViewController
在这里实现NetworkManagerListener
。我认为我使代码变得更加复杂,所以请帮助我了解我在做什么错以及如何消除此错误
import Alamofire
import EVReflection
import Alamofire_SwiftyJSON
import SwiftyJSON
protocol NetworkManagerListener {
associatedtype RES_TYPE
func successResponse(statusCode: Int, response: RES_TYPE?)
func errorResponse(statusCode: Int, error: ErrorResponse)
}
class NetworkingManager<RES: EVNetworkingObject, ER: ErrorResponse, T: Any> {
static func registerUser<BVC: BaseViewController<T>>(baseViewController: BVC, registerUserRequest: RegisterUserRequest, checkTokenExpiry: Bool) {
handleRequest(baseViewController: baseViewController, url: API.REGISTER_USER, requestModel: registerUserRequest, checkTokenExpiry: checkTokenExpiry)
}
private static func handleRequest<BVC: BaseViewController<T>, REQ: EVNetworkingObject>(baseViewController: BVC, url: String, requestModel: REQ, checkTokenExpiry: Bool) {
if let isReachable = NetworkReachabilityManager()?.isReachable, isReachable {
if let userModelDictionary = requestModel.toDictionary() as? Dictionary<String, Any> {
var headersDictionary: HTTPHeaders?
if let user = DatabaseManager.getUser() {
headersDictionary = [String: String]()
headersDictionary?["Authorization"] = "Bearer \(user.userToken)"
headersDictionary?["Content-Type"] = "application/json"
print(headersDictionary as Any)
}
Alamofire.request(url, method: .post, parameters: userModelDictionary, encoding: JSONEncoding.default, headers: headersDictionary ?? nil).validate(statusCode: 200..<300).responseSwiftyJSON { response in
if let statusCode = response.response?.statusCode {
do {
switch response.result {
case .failure(let error):
var errorResponse: ER = ER(message: "Please try again later")
if let data = try response.result.value?.rawData(), !data.isEmpty {
errorResponse = ER(data: data)
}
if checkTokenExpiry || statusCode >= STATUS_CODE.SERVER_ERROR_RANGE_STARTING {
handleErrorGlobally(baseViewController: baseViewController, statusCode: statusCode, errorResponse: errorResponse)
} else {
handleError(baseViewController: baseViewController, statusCode: statusCode, errorResponse: errorResponse)
}
break
case .success:
if let data = try response.result.value?.rawData(), let type = response.result.value?.type {
print("data: \(data)")
switch type {
case .array:
baseViewController.successResponse(statusCode: statusCode, response: [RES](data: data))
break
case .dictionary:
baseViewController.successResponse(statusCode: statusCode, response: RES.init(data: data))
break
default:
print("unhandled type: \(type)")
break
}
} else {
baseViewController.successResponse(statusCode: statusCode, response: nil as RES?)
}
break
}
} catch(let error) {
print("error: \(error)")
}
}
}
}
} else {
baseViewController.networkFailure()
}
}
private static func handleErrorGlobally<BVC: BaseViewController<T>, ER: ErrorResponse>(baseViewController: BVC, statusCode: Int, errorResponse: ER) {
if statusCode == STATUS_CODE.UN_AUTHORIZED {
baseViewController.tokenExpired()
} else if statusCode >= STATUS_CODE.SERVER_ERROR_RANGE_STARTING {
baseViewController.serverError()
} else {
baseViewController.networkError(statusCode, errorResponse)
}
}
private static func handleError<BVC: BaseViewController<T>, ER: ErrorResponse>(baseViewController: BVC, statusCode: Int, errorResponse: ER) {
baseViewController.errorResponse(statusCode: statusCode, error: errorResponse)
}
}
BaseViewController:
import UIKit
import EVReflection
class BaseViewController<RESPONSE_TYPE>: UIViewController, NetworkManagerListener {
typealias RES_TYPE = RESPONSE_TYPE
override func viewDidLoad() {
super.viewDidLoad()
}
func tokenExpired() {
//TODO: Need to create an alert dialog showing the user to re-login
print("Token expired")
}
func networkError(_ statusCode: Int, _ errorResponse: ErrorResponse) {
//general error with unhandled status code
let refreshAlert = UIAlertController(title: nil, message: errorResponse.message, preferredStyle: UIAlertController.Style.alert)
refreshAlert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
self.present(refreshAlert, animated: true, completion: nil)
}
func networkFailure() {
//handling no internet connection
let alert = UIAlertController(title: "Notice", message: "Please check your internet connection", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction.init(title: "Ok", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
func serverError() {
//TODO: Need to handle when error came from server
let alert = UIAlertController(title: "Notice", message: "Please try again later", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction.init(title: "Ok", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
func successResponse(statusCode: Int, response: RESPONSE_TYPE?) {
print("unhandled response is \(String(describing: response))")
}
func errorResponse(statusCode: Int, error: ErrorResponse) {
let alert = UIAlertController(title: nil, message: error.message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction.init(title: "Ok", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
示例响应:
import EVReflection
class RegisterUserResponse: EVNetworkingObject {
var userName: String?
var email: String?
var firstName: String?
var lastName: String?
override func propertyMapping() -> [(keyInObject: String?, keyInResource: String?)] {
return [("userName", "username"), ("firstName", "first_name"), ("lastName", "last_name")]
}
}
答案 0 :(得分:0)
您要传递的.successResponse必须覆盖/实现RESPONSE_TYPE,如在BaseViewController的typealias RES_TYPE中声明的那样。
class SomeListener: NetworkManagerListener {
typealias RES_TYPE = NSString
func successResponse(statusCode: Int, response: SomeListener.RES_TYPE?) {
}
func errorResponse(statusCode: Int, error: Int) {
}
}
class Res: NSString {
}
class Er {
}
class NetworkingManager<RES: Res, ER: Er, T: Any> {
func someCall() {
let a = SomeListener()
a.successResponse(statusCode: 1, response: Res())
}
}
在这种情况下,您应该尝试在BaseViewController中使用EVNetworkingObject切换RESPONSE_TYPE。