Author: pain

  • Async await trong swift – Part 1

    Async await trong swift – Part 1

    Apple đã giới thiệu cho cộng đồng dev iOS về Swift 5.5, trong đó có sự cập nhật rất là lớn. Đó là về bất đồng bộ, với async await

    Để xem async / await giúp ngôn ngữ như thế nào, sẽ hữu ích khi xem cách chúng tôi đã giải quyết vấn đề tương tự trước đây.

    Một ví dụ về networking trước khi async await được update

    class SeverConnection {
        let defaultSession = URLSession(configuration: URLSessionConfiguration.default)
        var dataTask: URLSessionDataTask?
        var downloadTask: URLSessionDownloadTask?
        var uploadTask: URLSessionUploadTask?
    }
    
    extension SeverConnection {
        func fetchAPIFromURL(_ url: String, completion: @escaping (String?, Error?) -> Void) {
            guard let url = URL(string: url) else {
                completion(nil, SeverConnectionError.badURL)
                return
            }
            dataTask = defaultSession.dataTask(with: url, completionHandler: { (data, response, error) in
                if let error = error {
                    completion(nil, SeverConnectionError.errorWithDataTask)
                    return
                }
                guard let httpResponse = response as? HTTPURLResponse,
                    (200...299).contains(httpResponse.statusCode) else {
                        completion(nil, SeverConnectionError.badResponse)
                        return
                }
                guard let data = data else { return }
                let dataString = String(data: data, encoding: .utf8)
                completion(dataString, nil)
            })
            dataTask?.resume()
        }
    }
    

    khi sử dụng:

    private func fetchListData() {
            let urlString = "https://vapor-mock.herokuapp.com/pic_dic.json"
            severConnection.fetchAPIFromURL(urlString) { [weak self] (data, error) in
                guard let self = self else {
                    return
                }
                if let error = error {
                    print(error)
                }
                if let data = data {
                    self.convertData(data)
                }
            }
        }
        
        private func convertData(_ data: String) {
            let responseData = Data(data.utf8)
            let decoder = JSONDecoder()
            
            var responseImageData: [ImageData]?
            
            do {
                responseImageData = try decoder.decode([ImageData].self, from: responseData)
                infoImages = responseImageData
                DispatchQueue.main.async {
                    self.mainTableView.reloadData()
                }
            } catch {
                print("Error decoding imageData: \(error)")
            }
        }
    

    Còn với async await

    class FetchAPITask {
        static let shared = FetchAPITask()
        
        func fetchAPI<D: Decodable>(url: URL) async throws -> D {
            let task = Task { () -> D in
                try await fetchAndDecode(url: url)
            }
            return try await task.value
        }
        
        func fetchAPIGroup<D: Decodable>(urls: [URL]) async throws -> [D] {
            try await withThrowingTaskGroup(of: D.self) { (group)  in
                for url in urls {
                    group.async { try await self.fetchAndDecode(url: url) }
                }
                var results = [D]()
                for try await result in group {
                    results.append(result)
                }
                return results
            }
        }
        
        func fetchAndDecode<D: Decodable>(url: URL) async throws -> D {
            let data = try await URLSession.shared.fetchData(with: url)
            let decodedData = try JSONDecoder().decode(D.self, from: data)
            return decodedData
        }
    }
    

    khi sử dụng:

    func fetchAllAPI() async {
        do {
            if let url = url {
                let datas: [ImageData] = try await FetchAPITask.shared.fetchAPI(url: url)
                self.datas = datas
            }
        } catch {
            print(error)
        }
    }
    
    Task.init(priority: .default, operation: {
        await self.fetchAllAPI()
        DispatchQueue.main.async {
            self.mainTableView.reloadData()
        }
    })
    

    Kết luận

    • Sử dụng async await với syntax đơn giản hơn dễ đọc hơn giúp việc đọc hiểu và maintain sẽ dễ dàng hơn
    • Các vấn đề với closure (điển hình như việc nhiều callback lồng nhau)
    • Đây là một ví dụ về việc sử dụng async await call api async await còn rất nhiều thứ hay ho mọi người có thể đọc tại đây
  • How To Create A Framework In Swift

    How To Create A Framework In Swift

    Updated for Swift 5

    Vì sao nên sử dụng framework

    • Việc sử dụng các tính chất hướng đối tượng trong lập trình rất phổ biến trong đó có tính chất kế thừa
    • Nhưng với việc swiftUI được ra đời và với SwiftUI thì View nó là struct, nên không thể kế thừa
    • Vậy có cách nào để thay thế được kế thừa trong swift?
    • Đối với riêng SwiftUI nói riêng hay việc sử dụng các framework iOS nói chung: Việc sử dụng tính chất kế thừa sẽ có những issue như swiftUI đang sử dụng View là struct ( struct k có các tính chất hướng đối tượng như class). Vâyviệc Customize 1 class để tái sử dụng như Class MainView: CustomizeView hay các phương thức như override hay class cha có các property gì thì class con cũng sẽ có các property đấy

    Tạo framework như thế nào?

    • Từ Xcode 11, Apple đã công bố tạo một framework được gọi là XCFramework
      • Mở Xcode, File > New > Project và chọn Framework

    • Triển khai mã code cho framwork tại đây
    • Tiếp theo sử dụng xcodebuild archive để tạo kho lưu trữ

      xcodebuild archive -scheme PROJECTNAME_HERE -destination=”iOS” -archivePath /tmp/xcf/ios.xcarchive -derivedDataPath /tmp/iphoneos -sdk iphoneos SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES

      xcodebuild archive -scheme PROJECTNAME_HERE -destination=”iOS Simulator” -archivePath /tmp/xcf/iossimulator.xcarchive -derivedDataPath /tmp/iphoneos -sdk iphonesimulator SKIP_INSTALL=NO BUILD_LIBRARIES_FOR_DISTRIBUTION=YES destination: tùy chọn xác định nền tảng mục tiêu và các thiết bị.archivePath: đường dẫn tới thư mục cần tạo framework

    • Sau khi chạy 2 lệnh ở trên thành công
    • Tiếp theo sử dung câu lệnh này để đóng gói framwork

      xcodebuild -create-xcframework -framework /tmp/xcf/ios.xcarchive/Products/Library/Frameworks/PROJECTNAME_HERE.framework -framework /tmp/xcf/iossimulator.xcarchive/Products/Library/Frameworks/PROJECTNAME_HERE.framework -output FRAMEWORK_NAME.xcframework

      File đã được gen ra thành công:

    • Add framework đã tạo vào trong project cần dùng và để sang Embed & Sign 
    • Import framework vào class cần sử dụng

    (more…)