在ios中从不同的View Controller(不是同时)多次调用相同的Web Service

时间:2018-05-08 08:00:56

标签: ios swift xcode rest

我只是想知道从不同的视图控制器(在不同的时间)调用相同的Web服务的最佳方法是什么。我应该遵循什么样的架构或设计?我不想在每个View Controller中编写相同的代码。

5 个答案:

答案 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) } } FirstChildViewControllerSecondChildViewController中编写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>