Я использую https://github.com/Mackis/NetworkLayer для сетевого процесса в моем приложении.
обычно я работаю так
networkManager.getServiceList { [weak self] (result, error) in
guard let self = self else { return }
if let error = error {
print(error)
}
if let result = result {
print(result)
}
}
, но когда дело доходит до загрузки нескольких изображений с параметрами я не мог понять это.
мой сценарий у меня есть 2 экрана. На первом экране я получаю значения, а затем отправляю второй v c
self.newShop = ShopKurumsal(email: email as! String,
name: (shopName as! String),
cityId: city.value?.id,
districtId: district.value?.id,
address: (longAddress as! String),
geoX: loc.coordinate.latitude,
geoY: loc.coordinate.longitude,
genderService: gender as? String,
description: (description as! String),
images: nil, price: self.selectedServices)
let vc = PickImageViewController(networkManager: self.networkManager)
vc.setShop(shop: self.newShop!)
self.navigationController?.pushViewController(vc, animated: true)
, во втором v c только часть изображения. Я использую библиотеку YangMingShan для выбора изображений. Я получаю изображения и красиво показываю их в виде коллекции. Теперь мне нужно добавить к изображениям и вызвать конечную точку createShop, как это
networkManager.createShop(shop: self.newShop!) { [weak self] (result, error) in
}
Мне нужно получить изображения на коллекцию и добавить в класс магазина как shop.append (images)
изображение Структура должна быть такой:
struct ShopImages: Codable {
var imageName: String?
var imageData: Data?
}
, а структура моего магазина -
struct ShopKurumsal: Codable {
var email: String?
var name: String?
var cityId: Int?
var districtId: Int?
var address: String?
var geoX: Double?
var geoY: Double?
var genderService: String?
var description: String?
var images: [ShopImages]?
var price: [ShopPrice]?
}
, и здесь я выбираю изображения из библиотеки
func photoPickerViewController(_ picker: YMSPhotoPickerViewController!, didFinishPickingImages photoAssets: [PHAsset]!) {
picker.dismiss(animated: true) {
let imageManager = PHImageManager.init()
let options = PHImageRequestOptions.init()
options.deliveryMode = .highQualityFormat
options.resizeMode = .exact
options.isSynchronous = true
let mutableImages: NSMutableArray! = []
for asset: PHAsset in photoAssets {
print(asset)
let scale = UIScreen.main.scale
let targetSize = CGSize(width: (self.collectionview.bounds.width - 20*2) * scale, height: (self.collectionview.bounds.height - 20*2) * scale)
imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options, resultHandler: { (image, info) in
mutableImages.add(image!)
})
}
self.images = mutableImages.copy() as? NSArray
self.collectionview.reloadData()
self.hideLoading()
}
}
моего сетевого менеджера метод создания магазина подобен этому
func createShop(shop: ShopKurumsal, completion: @escaping (_ shop: ShopCreateRespons?,_ error: String?)->()){
shopRouter.request(.createShop(model: shop)) { (data, response, error) in
if error != nil {
//completion(nil, "Please check your network connection.")
completion(nil, error?.localizedDescription)
}
if let response = response as? HTTPURLResponse {
let result = self.handleNetworkResponse(response)
switch result {
case .success:
guard let responseData = data else {
completion(nil, NetworkResponse.noData.rawValue)
return
}
do {
print(responseData)
let jsonData = try JSONSerialization.jsonObject(with: responseData, options: .mutableContainers)
print(jsonData)
let apiResponse = try JSONDecoder().decode(ShopCreateRespons.self, from: responseData)
completion(apiResponse,nil)
}catch {
print(error)
completion(nil, NetworkResponse.unableToDecode.rawValue)
}
case .failure(let networkFailureError):
completion(nil, networkFailureError)
}
}
}
}
конечная точка моего магазина
enum ShopNetworkEnvironment {
case qa
case production
case staging
}
enum ShopApi {
case createShop(model: ShopKurumsal)
}
extension ShopApi: EndPointType {
var environmentBaseURL : String {
switch NetworkManager.environment {
case .production: return "https://api"
case .qa: return "https://api/"
case .staging: return "/api/" //test
}
}
var baseURL: URL {
guard let url = URL(string: environmentBaseURL) else { fatalError("baseURL could not be configured.")}
return url
}
var path: String {
switch self {
case .createShop:
return "Shop/RegisterShop"
}
}
var httpMethod: HTTPMethod {
switch self {
case .getShops:
return .get
default:
return .post
}
}
var task: HTTPTask {
switch self {
case .createShop(let shop):
return .requestParameters(bodyParameters: ["Email": shop.email as Any,
"Name": shop.name as Any,
"CityId": shop.cityId as Any,
"DistrictId": shop.districtId as Any,
"Address": shop.address as Any,
"GEOX": shop.geoX as Any,
"GEOY": shop.geoY as Any,
"GenderService": shop.genderService as Any,
"Description": shop.description as Any,
"Images": shop.images as Any,
"PriceList": shop.price as Any
],
bodyEncoding: .jsonEncoding, urlParameters: nil)
default:
return .request
}
}
var headers: HTTPHeaders? {
return nil
}
}
тип конечной точки
protocol EndPointType {
var baseURL: URL { get }
var path: String { get }
var httpMethod: HTTPMethod { get }
var task: HTTPTask { get }
var headers: HTTPHeaders? { get }
}
и маршрутизатор:
public typealias NetworkRouterCompletion = (_ data: Data?,_ response: URLResponse?,_ error: Error?)->()
protocol NetworkRouter: class {
associatedtype EndPoint: EndPointType
func request(_ route: EndPoint, completion: @escaping NetworkRouterCompletion)
func cancel()
}
class Router<EndPoint: EndPointType>: NetworkRouter {
private var task: URLSessionTask?
func request(_ route: EndPoint, completion: @escaping NetworkRouterCompletion) {
let session = URLSession.shared
do {
let request = try self.buildRequest(from: route)
NetworkLogger.log(request: request)
task = session.dataTask(with: request, completionHandler: { data, response, error in
completion(data, response, error)
})
}catch {
completion(nil, nil, error)
}
self.task?.resume()
}
func cancel() {
self.task?.cancel()
}
fileprivate func buildRequest(from route: EndPoint) throws -> URLRequest {
var request = URLRequest(url: route.baseURL.appendingPathComponent(route.path),
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 10.0)
request.httpMethod = route.httpMethod.rawValue
do {
switch route.task {
case .request:
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
case .requestParameters(let bodyParameters,
let bodyEncoding,
let urlParameters):
try self.configureParameters(bodyParameters: bodyParameters,
bodyEncoding: bodyEncoding,
urlParameters: urlParameters,
request: &request)
case .requestParametersAndHeaders(let bodyParameters,
let bodyEncoding,
let urlParameters,
let additionalHeaders):
self.addAdditionalHeaders(additionalHeaders, request: &request)
try self.configureParameters(bodyParameters: bodyParameters,
bodyEncoding: bodyEncoding,
urlParameters: urlParameters,
request: &request)
}
return request
} catch {
throw error
}
}
fileprivate func configureParameters(bodyParameters: Parameters?,
bodyEncoding: ParameterEncoding,
urlParameters: Parameters?,
request: inout URLRequest) throws {
do {
try bodyEncoding.encode(urlRequest: &request,
bodyParameters: bodyParameters, urlParameters: urlParameters)
} catch {
throw error
}
}
fileprivate func addAdditionalHeaders(_ additionalHeaders: HTTPHeaders?, request: inout URLRequest) {
guard let headers = additionalHeaders else { return }
for (key, value) in headers {
request.setValue(value, forHTTPHeaderField: key)
}
}
}