我只是想知道从不同的视图控制器(在不同的时间)调用相同的Web服务的最佳方法是什么。我应该遵循什么样的架构或设计?我不想在每个View Controller中编写相同的代码。
答案 0 :(得分:0)
我会编写一个网络管理器类,它接受Web服务参数(如果有的话)作为参数。
以下是架构的粗略示例
class YourNetworkManager {
public func callSpecificWebService(argument : Type?, [optional closure to handle results]) {
// Generate the actual URL to be called here. Usually by
// appending a suffix to some constant base url
// The web service call mechanism goes here.
// This could either use the NSURLSession API
// or some third party library such as Alamofire
// Process the generic response conditions from the web service
// here. Pass on the specific parts to the calling method.
}
}
正如我所提到的,这是一个粗略的例子。您可以制作的模块化程度越高,就越好。
答案 1 :(得分:0)
如果使用Alamofire库我可以建议使用
class NetworkManager {
static let shared = NetworkManager()
static let alamofireManager: SessionManager = {
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.timeoutIntervalForRequest = TimeInterval(_TIMEOUT)
sessionConfiguration.timeoutIntervalForResource = TimeInterval(_TIMEOUT)
return Alamofire.SessionManager(configuration: sessionConfiguration)
}()
func performRequest(url: String,
method: HTTPMethod = .get,
parameters: [String: Any] = [String: Any](),
encoding: ParameterEncoding = URLEncoding.default,
contentType: String? = nil,
headers: HTTPHeaders = [String: String](),
success: @escaping(Data, Int) -> (),
failure: @escaping(CustomError) -> ()) {
debugPrint("NetworkManager is calling endpoint: \(url)")
NetworkManager.alamofireManager.request(url, method: method, parameters: parameters, encoding: encoding, headers: headers).validate().response { response in
guard let status = response.response?.statusCode, let data = response.data else {
if let error = response.error {
debugPrint("Error when calling endpoint \(url)")
failure(.unknownError(message: error.localizedDescription))
}
return
}
debugPrint("HTTP Status received: \(status)")
success(data, status)
}
} else {
failure(.noNetworkConnection)
}
}
请随意修改failure
处理程序以及您的自定义错误或您喜欢的任何内容。
当然,您需要序列化响应。
答案 2 :(得分:0)
为Alamofire请求创建一个基类:
import Alamofire
/// Struct for create AlamofireRequestModal
struct AlamofireRequestModal {
/// Struct constant for Alamofire.HTTPMethod
var method: Alamofire.HTTPMethod
/// Struct constant for path
var path: String
/// Struct constant for parameters
var parameters: [String: AnyObject]?
/// Struct constant for encoding:ParameterEncoding
var encoding: ParameterEncoding
/// Struct constant for headers
var headers: [String: String]?
///method to get init
init() {
method = .post
path = ""
parameters = nil
encoding = JSONEncoding() as ParameterEncoding
}
}
///BaseService to call the api's
class BaseService: NSObject {
/// network variable for Reachability
let network = Reachability.init(hostname: "https://www.google.com")
/**
This is method for call WebService into Alamofire
- parameter alamoReq: this is AlamofireRequestModal type request
- parameter success: success response
- parameter failure: failer object
*/
func callWebServiceAlamofire(_ alamoReq: AlamofireRequestModal, success:@escaping ((_ responseObject: AnyObject?) -> Void), failure:@escaping ((_ error: NSError?) -> Void)) {
guard (network?.isReachable)! else {
debugPrint("\n No Network Connection")
return
}
let request = Alamofire.request(alamoReq.path, method: alamoReq.method, parameters: alamoReq.parameters, encoding: alamoReq.encoding, headers: alamoReq.headers)
// Call response handler method of alamofire
request.validate(statusCode: 200..<600).responseJSON(completionHandler: { response in
let statusCode = response.response?.statusCode
if let allHeaderField = response.response {
allHeaderField.setHeaders()
}
switch response.result {
case .success(let data):
if statusCode == 200 {
success(data as AnyObject)
} else {
failure(NSError.init(domain: "www.wen.com", code: 101010, userInfo: ["message": "Something went wrong. Please trt again."]))
}
case .failure(let error):
failure(error as NSError?)
}
})
}
}
然后根据用途创建一个服务类,就像这里我创建用于登录和注册的Profile服务类和配置文件类型所有api都添加在这个类中,这样你就可以根据用途创建多个serice类:
import Alamofire
///Profile service to call the profile api's
class ProfileService: BaseService {
/**
This is request to BaseService to get Login
- parameter email: User email id
- parameter password: User password to login
- parameter success: success response
- parameter failure: failure response
*/
func doLogin(email: String, password: String, success: @escaping ((_ response: AnyObject?) -> Void), failure: @escaping ((_ error: NSError?) -> Void)) {
var request = AlamofireRequestModal()
request.path = "www.yourpath.com"
request.parameters = ["email": email as AnyObject,
"password": password as AnyObject
]
callWebServiceAlamofire(request, success: success, failure: failure)
}
}
现在,您可以从任何地方调用此配置文件服务的doLogin方法或者您可以创建更多层,如Model类,并从模型类调用此服务,或者您可以直接调用,如下所示:
ProfileService().doLogin(email: "Email", password: "Password", success: { (response) in
// Code here for handle success response
}) { (error) in
// Code here for handle error
}
答案 3 :(得分:0)
永远不要将Views
和/或ViewControllers
传递给您NetworkManager
课程。
假设您有一个类似NetworkManager
的类。
open class NetworkHelper {
class var sharedManager: NetworkHelper {
struct Static{
static let instance: NetworkHelper = NetworkHelper()
}
return Static.instance
}
func request(_ method: HTTPMethod, _ URLString: String, parameters: [String : AnyObject]? = [:], headers: [String : String]? = [:], completion:@escaping (Any?) -> Void, failure: @escaping (Error?) -> Void) {
let URL = "BASE_PATH" + "URLString"
Alamofire.request(URL, method: method, parameters: parameters, encoding: JSONEncoding.default, headers: headers)
.responseJSON { response in
switch response.result {
case .success:
completion(response.result.value!)
case .failure(let error):
failure(error)
guard error.localizedDescription == JSON_COULDNOT_SERIALISED else {
return
}
}
}
}
}
现在创建一个继承自BaseViewController
的{{1}},并使用必要的参数编写API调用。
例如,在API调用中,您只需要UIViewController
作为参数,其他所有内容都是userID
。
static
不,您应该继承那些您希望进行相同API调用的class BaseViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
func makeThisApiCallWithUserID(userId: Int) {
NetworkHelper.sharedManager.request(.get, "api/v1/yourApiAddress", parameters: ["userId":userId as AnyObject],headers: ["Authorization":"Bearer agshd81tebsf8724j"], completion: { (response) in
}) { (error) in
}
}
}
,并且您不想再次编写代码。
ViewController
请参阅我未在class FirstChildViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.makeThisApiCallWithUserID(userId: 123)
}
}
class SecondChildViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.makeThisApiCallWithUserID(userId: 13)
}
}
class ThirdChildViewController: BaseViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.makeThisApiCallWithUserID(userId: 3)
}
}
,FirstChildViewController
,SecondChildViewController
中编写API代码,但他们仍然可以使用不同的参数进行相同的API调用。
答案 4 :(得分:-1)
你使用Alamofire吗?如果是,那么我有很好的方法,用NetworkHelper Class编写。
<div>
<div class="my-grid-container" >
<div class="myClass" ng-repeat="cardData in summaryCardsCtrl.summaryDetails">
My custom div
</div>
</div>
</div>