Swift下将网络返回json数据转换成struct
假如网络请求返回的数据结构是一个深层嵌套的Json
首先要通过key-value取出这个json中的数据源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // 将返回的json字符串转Dictory let json = "" " { "name" : "jack" , "age" : 20 , "description" : "A student." } "" ". data ( using : . utf8 )! if let jsonData = jsonString . data ( using : . utf8 ) { do { let json = try JSONSerialization . jsonObject ( with : jsonData , options : []) if let dictionary = json as ? [ String : Any ], let key2 = dictionary [ "key2" ] as ? [ String : Any ], let innerKey2 = key2 [ "key2" ] as ? [ String : Any ], let value = innerKey2 [ "key1" ] as ? String { print ( value ) // 输出"value3" } } catch { print ( "解析JSON数据失败:(error)" ) } } |
数模转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | // 定义数据类型,遵守Codable协议 // 注意定义的类型与接口返回对应,否则JSONSerialization时崩溃 // Struct模型可以根据json中的数据关系对应嵌套 struct ContactSimpleModel : Codable { var relation : String var name : String struct ContactSimpleModel1 : Codable { var relation : String var name : String struct ContactSimpleModel2 : Codable { var relation : String var name : String } } } |
字典与struct互相转换
将字典转换成struct模型
根据网络返回的Dictory,从里面取出数组widgets: Array<[String: Any]>
1.map遍历数组,拿到每一个数组元素字典
2.处理每个元素,先使用JSONSerialization.data(withJSONObject:将字典转成data,
3.再使用JSONDecoder().decode(ContactSimpleModel.self, from: data)将data转成struct结构体。
4.使用struct模型
1 2 3 4 5 6 7 | let decoder = JSONDecoder () let resList = try widgets . map { ( item ) - > AdJsonModel in let data = try JSONSerialization . data ( withJSONObject : item , options : []) let res = try decoder . decode ( AdJsonModel . self , from : data ) return res } return resList |
struct模型转字典
也可以通过给Encodable协议加默认实现,提供便捷Struct转字典方法
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 扩展 Encodable 协议 extension Encodable { var dictionary : [ String : Any ]? { if let data = try ? JSONEncoder (). encode ( self ) { if let dict = try ? JSONSerialization . jsonObject ( with : data ) as ? [ String : Any ] { return dict } return nil } return nil } } |
Struct本地缓存
假如没有使用数据库,通过UserDefaults或者Plist文件保存。
使用data进行保存到UserDefaults
1 2 3 4 5 6 7 8 9 10 11 12 13 | struct Person : Codable { var name : String var age : Int } var people = [ Person ( name : "John" , age : 30 ), Person ( name : "Mary" , age : 25 )] //转成data保存 let data = try ! JSONEncoder (). encode ( people ) UserDefaults . standard . set ( data , forKey : "peopleData" ) //取 if let data = UserDefaults . standard . data ( forKey : "peopleData" ) { let people = try ! JSONDecoder (). decode ([ Person ]. self , from : data ) } |
使用Dictionary保存到Plist文件
本地文件处理
路径判断,创建目录用Url.path
创建目录案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | lazy var adListDirPath : String ? = { let documentDic = FileManager . default . urls ( for : . documentDirectory , in : . userDomainMask ). first let adUrl = documentDic ?. appendingPathComponent ( ":ad" ) if let adUrlSub = adUrl { var isDic : ObjCBool = ObjCBool ( false ) // 判断adUrlSub.path路径是否存在,如果是文件路径则isDic=false, 如果是目录路径isDic=true if FileManager . default . fileExists ( atPath : adUrlSub . path , isDirectory : & isDic ) & & isDic . boolValue { return adUrlSub . absoluteString } do { // 如果路径不存在,则创建本地路径,withIntermediateDirectories: true表示如果路径中间有未创建的,则把中间的目录也创建 try FileManager . default . createDirectory ( at : adUrlSub , withIntermediateDirectories : true , attributes : nil ) return adUrlSub . absoluteString } catch { Logger . error ( ":adDataManager" , content : error . localizedDescription ) return nil } } return nil }() |
写文件要用Url.absoluteString
swift中保存plist文件,使用NSDictionary进行保存
1 2 3 4 5 6 7 8 9 10 11 12 | 1 .先删除历史文件 do { try FileManager . default . removeItem ( at : filePathUrl ) return true } catch { Logger . error ( ":adDataManager" , content : error . localizedDescription ) return false } 2 .保存新文件 NSDictionary ( object : adList , forKey : adListRootKey ). write ( to : filePathUrl , atomically : true ) 3 .读取本地文件 let dict = try NSDictionary ( contentsOf : filePathUrl , error : ()) |
zip文件解压
1 2 3 4 5 6 7 8 9 | func unzipFile () { let zipPath = "/path/to/zip/file" let destinationPath = "/path/to/destination/folder" do { try ZipArchive . unzipFile ( atPath : zipPath , toDestination : destinationPath ) } catch { print ( "Error unzipping file: (error.localizedDescription)" ) } } |
先缓存后使用,提高用户体验
SDWebImage的先预下载图片,等启动时直接使用缓存的方法
1 2 3 4 5 6 7 8 | //0.自定义设置缓存大小 URLCache . shared = URLCache ( memoryCapacity : 10 * 1024 * 1024 , diskCapacity : 50 * 1024 * 1024 , diskPath : nil ) //1.缓存 SDWebImage 批量下载图片 SDWebImagePrefetcher . shared (). prefetchURLs 方法下载的图片本地路径默认是 Library / Caches / com . hackemist . SDWebImageCache . default 目录下的缓存文件。 可以通过 SDWebImageManager . shared (). imageCache . diskCachePath 方法获取具体路径。 //2.使用 在 UIImageView 加载图片时,使用 AAImageView . sd_setImage ( with : url , placeholderImage : nil )进行价值 |
1 2 | //3.删除缓存 SDWebImageManager . shared . imageCache . removeImage ( forKey : $ 0 , cacheType : SDImageCacheType . all ) |
注意:
对于可选类型的数组,如果没有拆包就map, 那么闭包的入参是拆包的数组
1 2 3 4 | let list = dict [ adListRootKey ] as ? Array < [ String : Any ] > if let listSub = list { let decoder = JSONDecoder () let resList = listSub . map { ( item ) - > AdJsonModel ? in |