设计网站都有哪些,邢台网站关键词优化,有了域名 做网站,h5网站开发软件1. 用到的技术点: 1) Codable : 可编/解码 JSON 数据 2) background threads : 后台线程 3) weak self : 弱引用 4) Combine : 取消器/组合操作 5) Publishers and Subscribers : 发布者与订阅者 6) FileManager : 文件管理器 7) NSCache : 缓存
2. 网址: 2.1 测试接口网址:
…1. 用到的技术点: 1) Codable : 可编/解码 JSON 数据 2) background threads : 后台线程 3) weak self : 弱引用 4) Combine : 取消器/组合操作 5) Publishers and Subscribers : 发布者与订阅者 6) FileManager : 文件管理器 7) NSCache : 缓存
2. 网址: 2.1 测试接口网址:
jsonplaceholderhttps://jsonplaceholder.typicode.com/ 2.2 JSON 转 Model 网址:
quicktypehttps://app.quicktype.io/
3. 项目结构图 4. Model 层 4.1 创建 PhotoModel.swift 文件
import Foundationstruct PhotoModel: Identifiable, Codable{let albumId: Intlet id: Intlet title: Stringlet url: Stringlet thumbnailUrl: String
}/*{albumId: 1,id: 1,title: accusamus beatae ad facilis cum similique qui sunt,url: https://via.placeholder.com/600/92c952,thumbnailUrl: https://via.placeholder.com/150/92c952}*/
5. 工具类 5.1 创建请求数据服务类PhotoModelDataService.swift
import Foundation
import Combine/// 请求数据服务
class PhotoModelDataService{// 单例模式 Singletonstatic let instance PhotoModelDataService()// 返回 JSON 数据解码成模型Published var photoModel:[PhotoModel] []// 随时取消请求var cancellables SetAnyCancellable()// 只能内部实例化保证一个 App 只有一次实例化private init() {downloadData()}// 测试接口网址: https://jsonplaceholder.typicode.com/// 下载数据func downloadData(){// 获取 URLguard let url URL(string: https://jsonplaceholder.typicode.com/photos) else { return }// 进行请求URLSession.shared.dataTaskPublisher(for: url).subscribe(on: DispatchQueue.global(qos: .background)).receive(on: DispatchQueue.main).tryMap(handleOutput).decode(type: [PhotoModel].self, decoder: JSONDecoder()).sink { completion inswitch(completion){case .finished:breakcase .failure(let error):print(Error downloading data. \(error))break}} receiveValue: { [weak self] returnedPhotoModel inguard let self self else { return }self.photoModel returnedPhotoModel}// 随时取消.store(in: cancellables)}// 输出数据private func handleOutput(output: URLSession.DataTaskPublisher.Output) throws - Data{guardlet response output.response as? HTTPURLResponse,response.statusCode 200 response.statusCode 300 else {throw URLError(.badServerResponse)}return output.data}
}5.2 创建图片缓存管理器类PhotoModelCacheManager.swift
import Foundation
import SwiftUI/// 图片缓存管理器
class PhotoModelCacheManager{// 单例模式static let instance PhotoModelCacheManager()// 只能内部实例化保证一个 App 只有一次实例化private init() {}// 图片数量缓存计算型属性var photoCache: NSCacheNSString, UIImage {let cache NSCacheNSString, UIImage()cache.countLimit 200cache.totalCostLimit 1024 * 1024 * 200 // 200mbreturn cache}()// 添加func add(key: String, value: UIImage){photoCache.setObject(value, forKey: key as NSString)}// 获取func get(key: String) - UIImage? {return photoCache.object(forKey: key as NSString)}
} 5.3 创建储存图片文件管理类PhotoModelFileManager.swift
import Foundation
import SwiftUI// 存储图片文件管理器
class PhotoModelFileManager{// 单例模式static let instance PhotoModelFileManager()let folderName downloaded_photosprivate init(){createFolderIfNeeded()}// 创建存放图片的目录private func createFolderIfNeeded(){guard let url getFolderPath() else { return }if !FileManager.default.fileExists(atPath: url.path){do {try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)print(Created folder success.)} catch let error {print(Error creating folder. \(error))}}}// 创建文件夹路径private func getFolderPath()- URL?{return FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent(folderName)}// .../downloaded_photos// .../downloaded_photos/image_name.png/// 获取图片路径/// - Parameter key: 名字/// - Returns: 图片路径private func getImagePath(key: String) - URL?{guard let folder getFolderPath() else { return nil}return folder.appendingPathComponent(key .png)}// 添加图片func add(key: String, value: UIImage){// 获取数据和路径guard let data value.pngData(),let url getImagePath(key: key) else { return }// 文件写人数据do {try data.write(to: url)print(Saving to file success.)} catch let error {print(Error saving to file manager. \(error))}}// 获取图片func get(key: String) - UIImage?{guardlet path getImagePath(key: key)?.path,FileManager.default.fileExists(atPath: path) else {//print(Error getting path.)return nil}return UIImage(contentsOfFile: path)}
}
6. ViewModel 层 6.1 创建下载图片 ViewModel 类DownloadingImageViewModel.swift
import Foundation
import Combineclass DownloadingImageViewModel: ObservableObject{// 数组模型Published var dataArray:[PhotoModel] []// 请求数据服务let dataService PhotoModelDataService.instance// 取消操作var cancellables SetAnyCancellable()init() {addSubscribers()}// 订阅数据func addSubscribers(){dataService.$photoModel.sink {[weak self] returnedPhotoModel inguard let self self else { return }self.dataArray returnedPhotoModel}.store(in: cancellables)}
}6.2 创建图片加载 ViewModel 类ImageLoadingViewModel.swift
import Foundation
import SwiftUI
import Combineclass ImageLoadingViewModel: ObservableObject{Published var image: UIImage?Published var isLoading: Bool false// 取消var cancellables SetAnyCancellable()// 缓存管理器let manager PhotoModelFileManager.instancelet urlString: Stringlet imageKey: Stringinit(url: String, key: String) {urlString urlimageKey keygetImage()}// 获取图片func getImage() {if let saveImage manager.get(key: imageKey){image saveImageprint(Getting saved image.)}else{downLoadImage()print(Downloading image now!)}}// 下载图片func downLoadImage(){isLoading trueguard let url URL(string: urlString) else {isLoading falsereturn}// 请求URLSession.shared.dataTaskPublisher(for: url).map { UIImage(data: $0.data) }.receive(on: DispatchQueue.main).sink { [weak self] _ inself?.isLoading false} receiveValue: { [weak self] returnedImage inguardlet self self,let image returnedImage else { return }self.image image// 下载的图像保存在缓存中self.manager.add(key: imageKey, value: image)}.store(in: cancellables)}
}
7. 创建 View 层 7.1 创建下载缓存显示图片视图DownloadingImageView.swift
import SwiftUI/// 下载缓存显示图片
struct DownloadingImageView: View {StateObject var loaderViewModel: ImageLoadingViewModelinit(url: String, key: String) {// _ : 加载器 wrappedValue: 包装器_loaderViewModel StateObject(wrappedValue: ImageLoadingViewModel(url: url, key: key))}var body: some View {ZStack {if loaderViewModel.isLoading{ProgressView()}else if let image loaderViewModel.image{Image(uiImage: image).resizable().clipShape(Circle())}}}
}struct DownloadingImageView_Previews: PreviewProvider {static var previews: some View {DownloadingImageView(url: https://via.placeholder.com/600/92c952, key: 1).frame(width: 75, height: 75).previewLayout(.sizeThatFits)}
}7.2 创建下载显示图片文字行视图DownloadingImagesRow.swift
import SwiftUIstruct DownloadingImagesRow: View {let model : PhotoModelvar body: some View {HStack {DownloadingImageView(url: model.url, key: \(model.id)).frame(width: 75, height: 75)VStack (alignment: .leading){Text(model.title).font(.headline)Text(model.url).foregroundColor(.gray).italic()}.frame( maxWidth: .infinity, alignment: .leading)}}
}struct DownloadingImagesRow_Previews: PreviewProvider {static var previews: some View {DownloadingImagesRow(model: PhotoModel(albumId: 1, id: 1, title: title, url: https://via.placeholder.com/600/92c952, thumbnailUrl: thumbnaolUrl here)).padding().previewLayout(.sizeThatFits)}
} 7.3 创建下载显示图片文字列表视图DownloadingImagesBootcamp.swift
import SwiftUI// Codable : 可编/解码 JSON 数据
// background threads : 后台线程
// weak self : 弱引用
// Combine : 取消器/组合操作
// Publishers and Subscribers : 发布者与订阅者
// FileManager : 文件管理器
// NSCache : 缓存struct DownloadingImagesBootcamp: View {StateObject var viewModel DownloadingImageViewModel()var body: some View {NavigationView {List {ForEach(viewModel.dataArray) { model inDownloadingImagesRow(model: model)}}.navigationTitle(Downloading Images)}}
}struct DownloadingImagesBootcamp_Previews: PreviewProvider {static var previews: some View {DownloadingImagesBootcamp()}
}
8. 效果图:
文章转载自: http://www.morning.ncfky.cn.gov.cn.ncfky.cn http://www.morning.nccyc.cn.gov.cn.nccyc.cn http://www.morning.bflwj.cn.gov.cn.bflwj.cn http://www.morning.bzgpj.cn.gov.cn.bzgpj.cn http://www.morning.ndyrb.com.gov.cn.ndyrb.com http://www.morning.ptqbt.cn.gov.cn.ptqbt.cn http://www.morning.qprtm.cn.gov.cn.qprtm.cn http://www.morning.gpryk.cn.gov.cn.gpryk.cn http://www.morning.ymhzd.cn.gov.cn.ymhzd.cn http://www.morning.ygwyt.cn.gov.cn.ygwyt.cn http://www.morning.qsszq.cn.gov.cn.qsszq.cn http://www.morning.rlkgc.cn.gov.cn.rlkgc.cn http://www.morning.supera.com.cn.gov.cn.supera.com.cn http://www.morning.rfbpq.cn.gov.cn.rfbpq.cn http://www.morning.yxzfl.cn.gov.cn.yxzfl.cn http://www.morning.ghqyr.cn.gov.cn.ghqyr.cn http://www.morning.bbyqz.cn.gov.cn.bbyqz.cn http://www.morning.rdxp.cn.gov.cn.rdxp.cn http://www.morning.bwqcx.cn.gov.cn.bwqcx.cn http://www.morning.nydgg.cn.gov.cn.nydgg.cn http://www.morning.snrhg.cn.gov.cn.snrhg.cn http://www.morning.wgqtt.cn.gov.cn.wgqtt.cn http://www.morning.hzqjgas.com.gov.cn.hzqjgas.com http://www.morning.lngyd.cn.gov.cn.lngyd.cn http://www.morning.jrkzk.cn.gov.cn.jrkzk.cn http://www.morning.xznrk.cn.gov.cn.xznrk.cn http://www.morning.trrpb.cn.gov.cn.trrpb.cn http://www.morning.ywrt.cn.gov.cn.ywrt.cn http://www.morning.xkjrq.cn.gov.cn.xkjrq.cn http://www.morning.dyfmh.cn.gov.cn.dyfmh.cn http://www.morning.kkjhj.cn.gov.cn.kkjhj.cn http://www.morning.dblfl.cn.gov.cn.dblfl.cn http://www.morning.tcylt.cn.gov.cn.tcylt.cn http://www.morning.ldqzz.cn.gov.cn.ldqzz.cn http://www.morning.jfch.cn.gov.cn.jfch.cn http://www.morning.gyzfp.cn.gov.cn.gyzfp.cn http://www.morning.pndhh.cn.gov.cn.pndhh.cn http://www.morning.pbtrx.cn.gov.cn.pbtrx.cn http://www.morning.zrlwl.cn.gov.cn.zrlwl.cn http://www.morning.kfhm.cn.gov.cn.kfhm.cn http://www.morning.kbqbx.cn.gov.cn.kbqbx.cn http://www.morning.smpb.cn.gov.cn.smpb.cn http://www.morning.bztzm.cn.gov.cn.bztzm.cn http://www.morning.nsmyj.cn.gov.cn.nsmyj.cn http://www.morning.pwlxy.cn.gov.cn.pwlxy.cn http://www.morning.rjnx.cn.gov.cn.rjnx.cn http://www.morning.cgtrz.cn.gov.cn.cgtrz.cn http://www.morning.touziyou.cn.gov.cn.touziyou.cn http://www.morning.nrcbx.cn.gov.cn.nrcbx.cn http://www.morning.pycpt.cn.gov.cn.pycpt.cn http://www.morning.jpfpc.cn.gov.cn.jpfpc.cn http://www.morning.lffrh.cn.gov.cn.lffrh.cn http://www.morning.ktlfb.cn.gov.cn.ktlfb.cn http://www.morning.rqdx.cn.gov.cn.rqdx.cn http://www.morning.qscsy.cn.gov.cn.qscsy.cn http://www.morning.yktwr.cn.gov.cn.yktwr.cn http://www.morning.wpwyx.cn.gov.cn.wpwyx.cn http://www.morning.hkcjx.cn.gov.cn.hkcjx.cn http://www.morning.jbshh.cn.gov.cn.jbshh.cn http://www.morning.nkpls.cn.gov.cn.nkpls.cn http://www.morning.ppdr.cn.gov.cn.ppdr.cn http://www.morning.nktxr.cn.gov.cn.nktxr.cn http://www.morning.fkyqt.cn.gov.cn.fkyqt.cn http://www.morning.wkhfg.cn.gov.cn.wkhfg.cn http://www.morning.duckgpt.cn.gov.cn.duckgpt.cn http://www.morning.fsjcn.cn.gov.cn.fsjcn.cn http://www.morning.rfqk.cn.gov.cn.rfqk.cn http://www.morning.qdlr.cn.gov.cn.qdlr.cn http://www.morning.pctsq.cn.gov.cn.pctsq.cn http://www.morning.gfnsh.cn.gov.cn.gfnsh.cn http://www.morning.zkrzb.cn.gov.cn.zkrzb.cn http://www.morning.jcxyq.cn.gov.cn.jcxyq.cn http://www.morning.jxwhr.cn.gov.cn.jxwhr.cn http://www.morning.zqzhd.cn.gov.cn.zqzhd.cn http://www.morning.tmnyj.cn.gov.cn.tmnyj.cn http://www.morning.ppwdh.cn.gov.cn.ppwdh.cn http://www.morning.qjngk.cn.gov.cn.qjngk.cn http://www.morning.zfqdt.cn.gov.cn.zfqdt.cn http://www.morning.qzxb.cn.gov.cn.qzxb.cn http://www.morning.zkzjm.cn.gov.cn.zkzjm.cn