iOS开发实战-第3节-解析json

本篇博客介绍了如何在iOS开发中使用Codable协议来解析JSON数据,包括理解Codable的可编码概念,以及Swift中的异常处理方法try?和guard语句的用法。同时提供了实战代码示例,如PostCell.swift、PostVIPBadge.swift和Post.swift。

本节内容

  1. Codable 解码以解析json
  2. swift 的异常处理方法

知识点

  • Codable 可编码

A type that can convert itself into and out of an external representation.

一个可以将自己转换为和脱离外部表示的类型。

通常是创建一个实例对象,在实例对象中创建与json文件相对应名称和类型的实例变量(实例变量可以少于json文件中对应名称的个数)。然后,将json文件解码成对应的实例对象,然后就可以通过实例对象进行全局访问。

  • try 异常处理

Swift2.0 后加入了新的关键字 try? , 如果不想处理异常那么可以用这个关键字,使用这个关键字返回一个可选值类型,如果有异常出现,返回nil.如果没有异常,则返回可选值。

- try 出现异常处理异常

- try? 不处理异常,返回一个可选值类型,出现异常返回nil

- try! 不让异常继续传播,一旦出现异常程序停止,类似NSAssert()
// 三种方法处理异常
// 方法1 推荐 try? 如果解析成功就有值,否则为 nil
let list1 = try?JSONDecoder().decode(PostList.self, from: data)
print(list1 ?? "None")
// 方法2 使用try 处理异常,能够接收到错误,并且输出。但是,语法结构复杂。
do {
    let list2 = try JSONDecoder().decode(PostList.self, from: data)
    print(list2);
} catch {
    print(error);
}
// 方法3 不推荐 try! 如果解析成功就有值,否则崩溃
let list3 = try!JSONDecoder().decode(PostList.self, from: data)
print(list3)
  • guard 守护

guard语句判断其后的表达式布尔值为false时,才会执行之后代码块里的代码,如果为true,则跳过整个guard语句。

guard expression else { 
    //语句
    //必须包含一个控制语句:return,break,continue或throw。
}

// 这里,expression是一个布尔表达式(返回true或者false)。
// 如果对表达式求值false,guard则执行代码块内的语句。
// 如果对表达式求值true,guard则从执行中跳过代码块内的语句

guard语句和if语句有点类似,都是根据其关键字之后的表达式的布尔值决定下一步执行什么。但与if语句不同的是,guard语句只会有一个代码块,不像if语句可以if else多个代码块。


guard let list = try?JSONDecoder().decode(PostList.self, from: data) else{
    fatalError("Can not parse post list json data")
}

实战代码

PostCell.swift

//
//  PostSell.swift
//  WeiboDemo
//
//  Created by EchoSun on 2020/11/29.
//

import SwiftUI

struct PostSell: View {
    let post:Post
    var body: some View {
        HStack(spacing: 5.0) {
            // 使用 library 窗口快速添加 ⇧⌘ L
            Image(uiImage: UIImage(named: post.avatar)!)
                .resizable() // 调整到合适的大小
                .scaledToFit()  // 按比例缩放
                
                // 下面两个语句顺序很关键,由于图片是矩形的,若这两句顺序颠倒,则最终效果是"直边椭圆形"。
                .clipShape(Circle())  // 切成一个圆形
                .frame(width:50, height: 50) // 设置大小
                
                //
                .overlay(
                    // 为了进一步简化代码,方便我们快速设置角标,我们将头像右下角的”V“抽象到一个新的视图中。
                    PostVIPBadge(vip:post.vip)
                        // 设置一个偏移量
                        .offset(x: 16, y: 16)
                )
            
            // VStack:纵向排列
            // leading: 左对齐
            // spacing: 四种间隔
            VStack(alignment: .leading, spacing: 5.0) {
                Text(post.name)  // 限制行数
                    .font(Font.system(size: 16))
                    .foregroundColor(.red)
                    .lineLimit(1)
                
                Text(post.date)
                    .font(Font.system(size: 11))
                    .foregroundColor(.gray)
            }
            .padding(.leading,10)
            
            Spacer() // 中间填充空间
            
            if !post.isFollowed{
                Button(action: {
                    print("Click follow button")
                }) {
                    Text("关注")
                        .font(.system(size: 14))
                        .foregroundColor(.orange)
                        .frame(width: 50, height: 26)  // 设置frame可以便于画矩形边框,也可以增大按键区域。
                        .overlay(
                            RoundedRectangle(cornerRadius: 13)
                                .stroke(Color.orange,lineWidth: 1) // 绘制轮廓
                        )
                }
            }
            
        }
    }
}

struct PostSell_Previews: PreviewProvider {
    static var previews: some View {
        PostSell(post: postList.list[0])
//        PostSell(post: Post(avata: "d0c21786ly1gavj2c0kcej20c8096dh7.jpg", vip: true, name: "用户昵称", date: "2020-1-1-1", isFollowed: false))
    }
}


PostVIPBadge.swift

//
//  PostVIPBadge.swift
//  WeiboDemo
//
//  Created by EchoSun on 2020/11/29.
//

import SwiftUI

struct PostVIPBadge: View {
    let vip:Bool
    var body: some View {
        Group {
            if vip{
                Text("V")
                    .bold()
                    .font(Font.system(size: 11))
                    .frame(width: 15, height: 15)
                    .foregroundColor(.yellow)
                    .background(Color.red)
                    
                    .clipShape(Circle())
                    .overlay(
                        RoundedRectangle(cornerRadius: 7.5)
                            .stroke(Color.white,lineWidth: 1)
                    )
            }
        }
    }
}

struct PostVIPBadge_Previews: PreviewProvider {
    static var previews: some View {
        PostVIPBadge(vip: true)
    }
}

Post.swift

//
//  Post.swift
//  WeiboDemo
//
//  Created by EchoSun on 2020/11/29.
//

import SwiftUI

// Codable 是一种可以编码和解码的数据类型
// 结构体与json的名称和类型必须对应,否则解析出错
struct PostList:Codable {
    var list:[Post]
}

// data model 看不到的数据模型
struct Post:Codable{
    // 下方的所有变量又叫做实例变量,仅在Post的实例创建时创建。
    // let 声明常量; var 声明变量. 不清楚的话可以先声明成常量,等到需要变动时再改成变量。
    let id:Int // 微博ID
    let avatar:String // 用户头像,图片名称
    let vip:Bool // 是否是VIP
    let name:String // 用户名
    let date:String // 日期
    var isFollowed:Bool // 是否关注
    
    let text:String // 微博内容
    let images:[String] // 微博图片
    
    var commentCount:Int // 评论数
    var likeCount:Int // 点赞数
    var isLiked:Bool  // 是否点赞
}

// 全局变量,任何地方都可以调用
let postList:PostList = loadPostListData(fileName:"PostListData_recommend_1.json")
func loadPostListData(fileName:String)->PostList{
    
    guard let url = Bundle.main.url(forResource: fileName, withExtension: nil) else{
        fatalError("Can not find \(fileName) in main Bundle")
    }
    guard let data = try? Data(contentsOf: url)else{
        fatalError("Can not load \(url)")
    }
    
//    // 三种方法处理异常
//    // 方法1 推荐 try? 如果解析成功就有值,否则为 nil
//    let list1 = try?JSONDecoder().decode(PostList.self, from: data)
//    print(list1 ?? "None")
//    // 方法2 使用try 处理异常,能够接收到错误,并且输出。但是,语法结构复杂。
//    do {
//        let list2 = try JSONDecoder().decode(PostList.self, from: data)
//        print(list2);
//    } catch {
//        print(error);
//    }
//    // 方法3 不推荐 try! 如果解析成功就有值,否则崩溃
//    let list3 = try!JSONDecoder().decode(PostList.self, from: data)
//    print(list3)
    
    guard let list = try?JSONDecoder().decode(PostList.self, from: data) else{
        fatalError("Can not parse post list json data")
    }
    return list
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值