วิธีแยกลอจิกการโต้ตอบระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ในแอปพลิเคชัน iOS

เผยแพร่แล้ว: 2022-03-11

ทุกวันนี้ แอปพลิเคชั่นมือถือส่วนใหญ่อาศัยการโต้ตอบระหว่างไคลเอนต์กับเซิร์ฟเวอร์เป็นอย่างมาก สิ่งนี้ไม่เพียงแค่หมายความว่าพวกเขาสามารถถ่ายโอนงานหนักส่วนใหญ่ไปยังเซิร์ฟเวอร์แบ็คเอนด์ได้ แต่ยังช่วยให้แอปพลิเคชั่นมือถือเหล่านี้นำเสนอคุณสมบัติและฟังก์ชั่นทุกประเภทที่สามารถใช้ได้ผ่านอินเทอร์เน็ตเท่านั้น

โดยปกติแล้ว เซิร์ฟเวอร์ส่วนหลังได้รับการออกแบบเพื่อให้บริการผ่าน RESTful API สำหรับแอปพลิเคชันที่ง่ายกว่า เรามักจะรู้สึกอยากได้รับโดยการสร้างโค้ดปาเก็ตตี้ โค้ดผสมที่เรียกใช้ API ด้วยตรรกะของแอปพลิเคชันที่เหลือ อย่างไรก็ตาม เนื่องจากแอปพลิเคชันมีความซับซ้อนและจัดการกับ API มากขึ้นเรื่อยๆ การโต้ตอบกับ API เหล่านี้ในลักษณะที่ไม่มีโครงสร้างและไม่ได้วางแผนอาจกลายเป็นเรื่องน่ารำคาญ

รักษาโค้ดแอปพลิเคชัน iOS ของคุณไม่ให้เกะกะด้วยโมดูลเครือข่ายไคลเอ็นต์ REST ที่ออกแบบมาอย่างดี

รักษาโค้ดแอปพลิเคชัน iOS ของคุณไม่ให้เกะกะด้วยโมดูลเครือข่ายไคลเอ็นต์ REST ที่ออกแบบมาอย่างดี
ทวีต

บทความนี้กล่าวถึงแนวทางสถาปัตยกรรมสำหรับการสร้างโมดูลเครือข่ายไคลเอ็นต์ REST ที่สะอาดหมดจดสำหรับแอปพลิเคชัน iOS ที่ช่วยให้คุณแยกตรรกะการโต้ตอบระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ทั้งหมดออกจากโค้ดแอปพลิเคชันส่วนที่เหลือ

แอปพลิเคชันไคลเอนต์ - เซิร์ฟเวอร์

การโต้ตอบระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์โดยทั่วไปมีลักษณะดังนี้:

  1. ผู้ใช้ดำเนินการบางอย่าง (เช่น แตะที่ปุ่มบางปุ่มหรือทำท่าทางอื่นๆ บนหน้าจอ)
  2. แอปพลิเคชันเตรียมและส่งคำขอ HTTP/REST เพื่อตอบสนองต่อการกระทำของผู้ใช้
  3. เซิร์ฟเวอร์ประมวลผลคำขอและตอบสนองตามแอปพลิเคชัน
  4. แอปพลิเคชันได้รับการตอบกลับและอัปเดตส่วนต่อประสานผู้ใช้ตามนั้น

เมื่อมองแวบเดียว กระบวนการโดยรวมอาจดูเรียบง่าย แต่เราต้องคิดถึงรายละเอียด

แม้ว่า API ของเซิร์ฟเวอร์แบ็กเอนด์จะทำงานตามที่โฆษณาไว้ (ซึ่ง ไม่ได้ เป็นเช่นนั้นเสมอไป!) ก็มักจะได้รับการออกแบบมาไม่ดี ทำให้ไม่มีประสิทธิภาพหรือใช้งานยาก สิ่งที่น่ารำคาญอย่างหนึ่งก็คือการเรียกใช้ API ทั้งหมดต้องการให้ผู้เรียกให้ข้อมูลเดียวกันซ้ำซ้อน (เช่น วิธีจัดรูปแบบข้อมูลคำขอ โทเค็นการเข้าถึงที่เซิร์ฟเวอร์สามารถใช้เพื่อระบุผู้ใช้ที่ลงชื่อเข้าใช้อยู่ในปัจจุบัน เป็นต้น)

แอปพลิเคชันมือถืออาจต้องใช้เซิร์ฟเวอร์แบ็คเอนด์หลายเครื่องพร้อมกันเพื่อวัตถุประสงค์ที่แตกต่างกัน ตัวอย่างเช่น เซิร์ฟเวอร์หนึ่งอาจใช้สำหรับการรับรองความถูกต้องของผู้ใช้ ในขณะที่อีกเซิร์ฟเวอร์หนึ่งเกี่ยวข้องกับการรวบรวมการวิเคราะห์เท่านั้น

นอกจากนี้ ไคลเอนต์ REST ทั่วไปจะต้องทำมากกว่าแค่เรียกใช้ API ระยะไกล ความสามารถในการยกเลิกคำขอที่รอดำเนินการ หรือแนวทางการจัดการข้อผิดพลาดที่ชัดเจนและจัดการได้ เป็นตัวอย่างของฟังก์ชันการทำงานที่จำเป็นต้องสร้างขึ้นในแอปพลิเคชันมือถือที่มีประสิทธิภาพ

ภาพรวมของสถาปัตยกรรม

แกนหลักของไคลเอนต์ REST ของเราจะสร้างจากส่วนประกอบต่อไปนี้:

  • โมเดล: คลาสที่อธิบายโมเดลข้อมูลของแอปพลิเคชันของเรา ซึ่งสะท้อนถึงโครงสร้างของข้อมูลที่ได้รับหรือส่งไปยังเซิร์ฟเวอร์แบ็กเอนด์
  • Parsers: รับผิดชอบในการถอดรหัสการตอบสนองของเซิร์ฟเวอร์และสร้างโมเดลวัตถุ
  • ข้อผิดพลาด: ออบเจ็กต์ที่แสดงถึงการตอบสนองของเซิร์ฟเวอร์ที่ผิดพลาด
  • ไคลเอนต์: ส่งคำขอไปยังเซิร์ฟเวอร์แบ็กเอนด์และรับการตอบกลับ
  • บริการ: จัดการการดำเนินการที่เชื่อมโยงทางตรรกะ (เช่น การพิสูจน์ตัวตน การจัดการข้อมูลที่เกี่ยวข้องกับผู้ใช้ การวิเคราะห์ ฯลฯ)

นี่คือวิธีที่แต่ละองค์ประกอบเหล่านี้จะโต้ตอบกัน:

ลูกศร 1 ถึง 10 ในภาพด้านบนแสดงลำดับการดำเนินการในอุดมคติระหว่างแอปพลิเคชันที่เรียกใช้บริการและบริการส่งคืนข้อมูลที่ร้องขอเป็นวัตถุแบบจำลองในที่สุด แต่ละองค์ประกอบในโฟลว์นั้นมีบทบาทเฉพาะทำให้มั่นใจได้ถึงการแยกข้อกังวลภายในโมดูล

การดำเนินการ

เราจะใช้ไคลเอ็นต์ REST ของเราเป็นส่วนหนึ่งของแอปพลิเคชันเครือข่ายสังคมในจินตนาการ ซึ่งเราจะโหลดรายชื่อเพื่อนของผู้ใช้ที่เข้าสู่ระบบอยู่ในปัจจุบัน เราจะถือว่าเซิร์ฟเวอร์ระยะไกลของเราใช้ JSON สำหรับการตอบกลับ

ให้เราเริ่มต้นด้วยการนำโมเดลและ parsers ของเราไปใช้

จาก Raw JSON สู่ Model Objects

โมเดลแรกของเรา User กำหนดโครงสร้างของข้อมูลสำหรับผู้ใช้โซเชียลเน็ตเวิร์ก เพื่อให้ง่ายขึ้น เราจะรวมเฉพาะฟิลด์ที่จำเป็นสำหรับบทช่วยสอนนี้เท่านั้น (ในการใช้งานจริง โครงสร้างมักจะมีคุณสมบัติมากกว่านั้นมาก)

 struct User { var id: String var email: String? var name: String? }

เนื่องจากเราจะได้รับข้อมูลผู้ใช้ทั้งหมดจากเซิร์ฟเวอร์ส่วนหลังผ่าน API เราจึงต้องการวิธีแยกวิเคราะห์การตอบสนอง API เป็นวัตถุ User ที่ถูกต้อง ในการทำเช่นนี้ เราจะเพิ่มคอนสตรัคเตอร์ให้กับ User ที่ยอมรับอ็อบเจกต์ JSON ที่แยกวิเคราะห์ ( Dictionary ) เป็นพารามิเตอร์ เราจะกำหนดวัตถุ JSON ของเราเป็นประเภทนามแฝง:

 typealias JSON = [String: Any]

จากนั้นเราจะเพิ่มฟังก์ชันตัวสร้างให้กับโครงสร้าง User ของเราดังนี้:

 extension User { init?(json: JSON) { guard let id = json["id"] as? String else { return nil } self.id = id self.email = json["email"] as? String self.name = json["name"] as? String } }

เพื่อรักษาคอนสตรัคเตอร์เริ่มต้นดั้งเดิมของ User เราเพิ่มคอนสตรัคเตอร์ผ่านส่วนขยายในประเภท User

ต่อไป เพื่อสร้างวัตถุ User จากการตอบสนอง API ดิบ เราจำเป็นต้องดำเนินการสองขั้นตอนต่อไปนี้:

 // Transform raw JSON data to parsed JSON object using JSONSerializer (part of standard library) let userObject = (try? JSONSerialization.jsonObject(with: data, options: [])) as? JSON // Create an instance of `User` structure from parsed JSON object let user = userObject.flatMap(User.init)

การจัดการข้อผิดพลาดที่คล่องตัว

เราจะกำหนดประเภทเพื่อแสดงข้อผิดพลาดต่างๆ ที่อาจเกิดขึ้นเมื่อพยายามโต้ตอบกับเซิร์ฟเวอร์แบ็กเอนด์ เราสามารถแบ่งข้อผิดพลาดดังกล่าวทั้งหมดออกเป็นสามประเภทพื้นฐาน:

  • ไม่มีการเชื่อมต่ออินเทอร์เน็ต
  • ข้อผิดพลาดที่รายงานเป็นส่วนหนึ่งของการตอบสนอง (เช่น ข้อผิดพลาดในการตรวจสอบ สิทธิ์การเข้าถึงไม่เพียงพอ ฯลฯ)
  • ข้อผิดพลาดที่เซิร์ฟเวอร์ไม่สามารถรายงานเป็นส่วนหนึ่งของการตอบสนอง (เช่น เซิร์ฟเวอร์ขัดข้อง หมดเวลาตอบสนอง ฯลฯ)

เราสามารถกำหนดวัตถุข้อผิดพลาดของเราเป็นประเภทการแจงนับ และในขณะที่เรากำลังดำเนินการอยู่ ควรทำให้ประเภท ServiceError ของเราสอดคล้องกับโปรโตคอล Error ซึ่งจะทำให้เราใช้และจัดการค่าความผิดพลาดเหล่านี้ได้โดยใช้กลไกมาตรฐานที่ Swift จัดเตรียมไว้ให้ (เช่น การใช้ throw to throw an error)

 enum ServiceError: Error { case noInternetConnection case custom(String) case other }

ไม่เหมือนกับ noInternetConnection และข้อผิดพลาด other ข้อผิดพลาดที่กำหนดเองมีค่าที่เกี่ยวข้อง ซึ่งจะทำให้เราใช้การตอบสนองข้อผิดพลาดจากเซิร์ฟเวอร์เป็นค่าที่เกี่ยวข้องสำหรับข้อผิดพลาดนั้นเอง ซึ่งจะทำให้ข้อผิดพลาดมีบริบทมากขึ้น

ตอนนี้ มาเพิ่มคุณสมบัติ errorDescription ให้กับ ServiceError enumartion เพื่อให้ข้อผิดพลาดมีรายละเอียดมากขึ้น เราจะเพิ่มข้อความฮาร์ดโค้ดสำหรับ noInternetConnection และข้อผิดพลาด other และใช้ค่าที่เกี่ยวข้องเป็นข้อความสำหรับข้อผิดพลาด custom

 extension ServiceError: LocalizedError { var errorDescription: String? { switch self { case .noInternetConnection: return "No Internet connection" case .other: return "Something went wrong" case .custom(let message): return message } } }

มีอีกสิ่งหนึ่งที่เราต้องนำไปใช้ในการแจงนับ ServiceError ของเรา ในกรณีของข้อผิดพลาด custom เราจำเป็นต้องแปลงข้อมูล JSON ของเซิร์ฟเวอร์ให้เป็นวัตถุข้อผิดพลาด ในการทำเช่นนี้ เราใช้แนวทางเดียวกันกับที่ใช้ในกรณีของแบบจำลอง:

 extension ServiceError { init(json: JSON) { if let message = json["message"] as? String { self = .custom(message) } else { self = .other } } }

เชื่อมช่องว่างระหว่างแอปพลิเคชันและเซิร์ฟเวอร์แบ็กเอนด์

ส่วนประกอบไคลเอนต์จะเป็นตัวกลางระหว่างแอปพลิเคชันและเซิร์ฟเวอร์ส่วนหลัง เป็นองค์ประกอบสำคัญที่จะกำหนดวิธีที่แอปพลิเคชันและเซิร์ฟเวอร์จะสื่อสารกัน แต่จะไม่รู้อะไรเกี่ยวกับโมเดลข้อมูลและโครงสร้างของพวกเขา ลูกค้าจะต้องรับผิดชอบในการเรียกใช้ URL เฉพาะด้วยพารามิเตอร์ที่ให้ไว้และส่งคืนข้อมูล JSON ขาเข้าที่แยกวิเคราะห์เป็นออบเจ็กต์ JSON

 enum RequestMethod: String { case get = "GET" case post = "POST" case put = "PUT" case delete = "DELETE" } final class WebClient { private var baseUrl: String init(baseUrl: String) { self.baseUrl = baseUrl } func load(path: String, method: RequestMethod, params: JSON, completion: @escaping (Any?, ServiceError?) -> ()) -> URLSessionDataTask? { // TODO: Add implementation } }

ลองดูว่าเกิดอะไรขึ้นในโค้ดด้านบนนี้…

ขั้นแรก เราประกาศประเภทการแจงนับ RequestMethod ซึ่งอธิบายวิธี HTTP ทั่วไปสี่วิธี นี่เป็นวิธีการที่ใช้ใน REST API

คลาส WebClient มีคุณสมบัติ baseURL ซึ่งจะใช้เพื่อแก้ไข URL ที่เกี่ยวข้องทั้งหมดที่ได้รับ ในกรณีที่แอปพลิเคชันของเราต้องการโต้ตอบกับเซิร์ฟเวอร์หลายเครื่อง เราสามารถสร้าง WebClient ได้หลายอินสแตนซ์ โดยแต่ละรายการมีค่าต่างกันสำหรับ baseURL

ไคลเอ็นต์มีเมธอดเดียว load ซึ่งใช้พาธที่สัมพันธ์กับ baseURL เป็นพารามิเตอร์ วิธีการขอ พารามิเตอร์คำขอ และการปิดเสร็จสิ้น การปิดเสร็จสิ้นถูกเรียกใช้ด้วย JSON และ ServiceError ที่แยกวิเคราะห์เป็นพารามิเตอร์ สำหรับตอนนี้ วิธีการข้างต้นยังไม่มีการนำไปปฏิบัติ ซึ่งเราจะทำในไม่ช้านี้

ก่อนใช้วิธีการ load เราต้องการวิธีสร้าง URL จากข้อมูลทั้งหมดที่มีให้กับเมธอด เราจะขยายคลาส URL เพื่อจุดประสงค์นี้:

 extension URL { init(baseUrl: String, path: String, params: JSON, method: RequestMethod) { var components = URLComponents(string: baseUrl)! components.path += path switch method { case .get, .delete: components.queryItems = params.map { URLQueryItem(name: $0.key, value: String(describing: $0.value)) } default: break } self = components.url! } }

ที่นี่เราเพียงแค่เพิ่มเส้นทางไปยัง URL ฐาน สำหรับเมธอด GET และ DELETE HTTP เรายังเพิ่มพารามิเตอร์การสืบค้นลงในสตริง URL

ต่อไป เราต้องสามารถสร้างอินสแตนซ์ของ URLRequest จากพารามิเตอร์ที่กำหนดได้ ในการดำเนินการนี้ เราจะทำบางสิ่งที่คล้ายกับที่เราทำกับ URL :

 extension URLRequest { init(baseUrl: String, path: String, method: RequestMethod, params: JSON) { let url = URL(baseUrl: baseUrl, path: path, params: params, method: method) self.init(url: url) httpMethod = method.rawValue setValue("application/json", forHTTPHeaderField: "Accept") setValue("application/json", forHTTPHeaderField: "Content-Type") switch method { case .post, .put: httpBody = try! JSONSerialization.data(withJSONObject: params, options: []) default: break } } }

ที่นี่ ก่อนอื่นเราสร้าง URL โดยใช้ตัวสร้างจากส่วนขยาย จากนั้น เราเริ่มต้นอินสแตนซ์ของ URLRequest ด้วย URL นี้ ตั้งค่าส่วนหัว HTTP บางส่วนตามความจำเป็น จากนั้นในกรณีของวิธี POST หรือ PUT HTTP ให้เพิ่มพารามิเตอร์ลงในเนื้อหาคำขอ

ตอนนี้เราได้ครอบคลุมข้อกำหนดเบื้องต้นทั้งหมดแล้ว เราสามารถใช้วิธีการ load ได้:

 final class WebClient { private var baseUrl: String init(baseUrl: String) { self.baseUrl = baseUrl } func load(path: String, method: RequestMethod, params: JSON, completion: @escaping (Any?, ServiceError?) -> ()) -> URLSessionDataTask? { // Checking internet connection availability if !Reachability.isConnectedToNetwork() { completion(nil, ServiceError.noInternetConnection) return nil } // Adding common parameters var parameters = params if let token = KeychainWrapper.itemForKey("application_token") { parameters["token"] = token } // Creating the URLRequest object let request = URLRequest(baseUrl: baseUrl, path: path, method: method, params: params) // Sending request to the server. let task = URLSession.shared.dataTask(with: request) { data, response, error in // Parsing incoming data var object: Any? = nil if let data = data { object = try? JSONSerialization.jsonObject(with: data, options: []) } if let httpResponse = response as? HTTPURLResponse, (200..<300) ~= httpResponse.statusCode { completion(object, nil) } else { let error = (object as? JSON).flatMap(ServiceError.init) ?? ServiceError.other completion(nil, error) } } task.resume() return task } }

วิธีการ load ด้านบนดำเนินการตามขั้นตอนต่อไปนี้:

  1. ตรวจสอบความพร้อมใช้งานของการเชื่อมต่ออินเทอร์เน็ต หากไม่มีการเชื่อมต่ออินเทอร์เน็ต เราจะเรียกการปิดการดำเนินการทันทีโดยไม่มีข้อผิดพลาด noInternetConnection เป็นพารามิเตอร์ (หมายเหตุ: ความสามารถในการ Reachability ในโค้ดเป็นคลาสที่กำหนดเอง ซึ่งใช้หนึ่งในวิธีทั่วไปในการตรวจสอบการเชื่อมต่ออินเทอร์เน็ต)
  2. เพิ่มพารามิเตอร์ทั่วไป . ซึ่งอาจรวมถึงพารามิเตอร์ทั่วไป เช่น โทเค็นของแอปพลิเคชันหรือ ID ผู้ใช้
  3. สร้างวัตถุ URLRequest โดยใช้ตัวสร้างจากส่วนขยาย
  4. ส่งคำขอไปยังเซิร์ฟเวอร์ เราใช้วัตถุ URLSession เพื่อส่งข้อมูลไปยังเซิร์ฟเวอร์
  5. แยกวิเคราะห์ข้อมูลที่เข้ามา เมื่อเซิร์ฟเวอร์ตอบสนอง ก่อนอื่นเราจะแยกวิเคราะห์ payload การตอบสนองเป็นวัตถุ JSON โดยใช้ JSONSerialization จากนั้นเราจะตรวจสอบรหัสสถานะของการตอบกลับ หากเป็นรหัสความสำเร็จ (เช่น ในช่วงระหว่าง 200 ถึง 299) เราจะเรียกการปิดสำเร็จด้วยวัตถุ JSON มิฉะนั้น เราจะแปลงวัตถุ JSON เป็นวัตถุ ServiceError และเรียกการปิดเสร็จสมบูรณ์ด้วยวัตถุข้อผิดพลาดนั้น

การกำหนดบริการสำหรับการดำเนินการที่เชื่อมโยงเชิงตรรกะ

ในกรณีของแอปพลิเคชันของเรา เราต้องการบริการที่จะจัดการกับงานที่เกี่ยวข้องกับเพื่อนของผู้ใช้ สำหรับสิ่งนี้ เราสร้างคลาส FriendsService ตามหลักการแล้ว ชั้นเรียนในลักษณะนี้จะรับผิดชอบการดำเนินงาน เช่น การรับรายชื่อเพื่อน เพิ่มเพื่อนใหม่ การลบเพื่อน การจัดกลุ่มเพื่อนเป็นหมวดหมู่ เป็นต้น เพื่อความง่ายในบทช่วยสอนนี้ เราจะใช้วิธีเดียว :

 final class FriendsService { private let client = WebClient(baseUrl: "https://your_server_host/api/v1") @discardableResult func loadFriends(forUser user: User, completion: @escaping ([User]?, ServiceError?) -> ()) -> URLSessionDataTask? { let params: JSON = ["user_id": user.id] return client.load(path: "/friends", method: .get, params: params) { result, error in let dictionaries = result as? [JSON] completion(dictionaries?.flatMap(User.init), error) } } }

คลาส FriendsService มีคุณสมบัติ client ประเภท WebClient เริ่มต้นด้วย URL พื้นฐานของเซิร์ฟเวอร์ระยะไกลซึ่งมีหน้าที่ในการจัดการเพื่อน ดังที่กล่าวไว้ก่อนหน้านี้ ในคลาสบริการอื่นๆ เราสามารถมีอินสแตนซ์ที่แตกต่างกันของ WebClient ที่เริ่มต้นด้วย URL อื่นได้หากจำเป็น

ในกรณีของแอปพลิเคชันที่ทำงานกับเซิร์ฟเวอร์เดียวเท่านั้น คลาส WebClient สามารถกำหนดคอนสตรัคเตอร์ที่เริ่มต้นด้วย URL ของเซิร์ฟเวอร์นั้น:

 final class WebClient { // ... init() { self.baseUrl = "https://your_server_base_url" } // ... }

เมื่อเรียกใช้เมธอด loadFriends จะเตรียมพารามิเตอร์ที่จำเป็นทั้งหมดและใช้อินสแตนซ์ของ WebClient ของ FriendService เพื่อส่งคำขอ API หลังจากที่ได้รับการตอบกลับจากเซิร์ฟเวอร์ผ่าน WebClient มันจะแปลงวัตถุ JSON เป็นโมเดล User และเรียกการปิดที่เสร็จสมบูรณ์โดยใช้วัตถุเหล่านี้เป็นพารามิเตอร์

การใช้งาน FriendService โดยทั่วไปอาจมีลักษณะดังนี้:

 let friendsTask: URLSessionDataTask! let activityIndicator: UIActivityIndicatorView! var friends: [User] = [] func friendsButtonTapped() { friendsTask?.cancel() //Cancel previous loading task. activityIndicator.startAnimating() //Show loading indicator friendsTask = FriendsService().loadFriends(forUser: currentUser) {[weak self] friends, error in DispatchQueue.main.async { self?.activityIndicator.stopAnimating() //Stop loading indicators if let error = error { print(error.localizedDescription) //Handle service error } else if let friends = friends { self?.friends = friends //Update friends property self?.updateUI() //Update user interface } } } }

ในตัวอย่างข้างต้น เราถือว่าฟังก์ชัน friendsButtonTapped ถูกเรียกใช้เมื่อใดก็ตามที่ผู้ใช้แตะปุ่มที่ต้องการแสดงรายการเพื่อนในเครือข่าย เรายังเก็บการอ้างอิงถึงงานในคุณสมบัติ friendsTask เพื่อให้เราสามารถยกเลิกคำขอได้ตลอดเวลาโดยเรียก friendsTask?.cancel()

ซึ่งช่วยให้เราควบคุมวงจรชีวิตของคำขอที่รอดำเนินการได้ดียิ่งขึ้น ทำให้เราสามารถยุติคำขอได้เมื่อเราพิจารณาแล้วว่าคำขอเหล่านี้ไม่เกี่ยวข้อง

บทสรุป

ในบทความนี้ ฉันได้แชร์สถาปัตยกรรมแบบง่ายของโมดูลเครือข่ายสำหรับแอปพลิเคชัน iOS ของคุณ ซึ่งทั้งการใช้งานเพียงเล็กน้อยและสามารถปรับให้เข้ากับความต้องการด้านเครือข่ายที่ซับซ้อนของแอปพลิเคชัน iOS ส่วนใหญ่ได้ อย่างไรก็ตาม ประเด็นสำคัญจากสิ่งนี้คือไคลเอ็นต์ REST และส่วนประกอบที่ออกแบบมาอย่างเหมาะสมซึ่งแยกจากตรรกะแอปพลิเคชันที่เหลือของคุณ สามารถช่วยให้รหัสการโต้ตอบระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ของแอปพลิเคชันของคุณเรียบง่าย แม้ว่าแอปพลิเคชันเองจะมีความซับซ้อนมากขึ้น .

ฉันหวังว่าคุณจะพบว่าบทความนี้มีประโยชน์ในการสร้างแอปพลิเคชัน iOS ตัวต่อไปของคุณ คุณสามารถค้นหาซอร์สโค้ดของโมดูลเครือข่ายนี้ได้บน GitHub ตรวจสอบรหัส แยกมัน เปลี่ยนมัน เล่นกับมัน

หากคุณพบว่าสถาปัตยกรรมอื่นๆ เหมาะสมกว่าสำหรับคุณและโครงการของคุณ โปรดแบ่งปันรายละเอียดในส่วนความคิดเห็นด้านล่าง

ที่เกี่ยวข้อง: ลดความซับซ้อนของการใช้ RESTful API และการคงอยู่ของข้อมูลบน iOS ด้วย Mantle และ Realm