GVKun编程网logo

Codable: 实现在 swift 中像 js 那样使用 JSON(codice swift)

1

针对Codable:实现在swift中像js那样使用JSON和codiceswift这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展Android通过onDraw实现在View中绘图操作、C

针对Codable: 实现在 swift 中像 js 那样使用 JSONcodice swift这两个问题,本篇文章进行了详细的解答,同时本文还将给你拓展Android 通过 onDraw 实现在 View 中绘图操作、Codable - 更好的使用 code 字段、ios – Swift:Codable – 提取单个编码密钥、java 集成 pageoffice 实现在 word 中插入表格并赋值等相关知识,希望可以帮助到你。

本文目录一览:

Codable: 实现在 swift 中像 js 那样使用 JSON(codice swift)

Codable: 实现在 swift 中像 js 那样使用 JSON(codice swift)

Codable: 实现在 swift 中像 js 那样使用 JSON

官方文档,关于 Codable 实现:https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types

js 一样,iOS 11 之后,swift 也可以方便的使用 json 来传递数据了。

要想使用 json, 你操作的类需要实现 Codable 接口
Foundation 中的所有类都已经实现了 Cadable,所以如果你的实体中没有自定义的一些数据类型,都可以直接使用 JSON

js 一样,swift 中的 json 也有:

  • JSONEncoder 将数据转成 json 数据
  • JOSNDecoderjson 数据,转为可用的你需要的数据类型

看下面的 PlayGround 例子便知道如何使用了

由对象转字符串

import Foundation

struct Person: Codable {
    var name: String
    var age: Int
    var intro: String
}

let kyle = Person(name: "Kyle", age: 29, intro: "A web developer")
let tina = Person(name: "Tina", age: 26, intro: "A teacher for English")
let persons = [kyle, tina]

// Encode
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted // setup formatter
let jsonData = try encoder.encode(persons)
print(String(data: jsonData, encoding: .utf8)!)


// Decode
let decoder = JSONDecoder()
// 注意 decode() 中的第一个参数
let people = try decoder.decode(Array<Person>.self, from: jsonData)
print(people[0].name)

输出如下:

[
  {
    "name" : "Kyle",
    "age" : 29,
    "intro" : "A web developer"
  },
  {
    "name" : "Tina",
    "age" : 26,
    "intro" : "A teacher for English"
  }
]
Kyle

由字符串转对象

import Foundation

struct Person: Codable {
    let name: String
    let age: Int
    let intro: String
}

let jsonString = """
[
    {
        "name": "Kyle",
        "age": 27,
        "intro": "A font-end enginer",
        "location": "Jinan"
    },
    {
        "name": "Tina",
        "age": 26,
        "intro": "A UI enginer",
        "location": "Jinan"
    }
]
"""

// 1. 先从字符串转为 Data
let jsonData = jsonString.data(using: .utf8)!

// 2. 再用 Data 转成对应的对象
let decoder = JSONDecoder()
let persons = try decoder.decode(Array<Person>.self, from: jsonData)

print(type(of: persons[0]))

cadable.png

对象名与 json 名不一致时

有些时候,对象声明中的变量名跟json中的键名不一致,如 nameEn 在 json 中需要为 json_en
只需要在对象声明中用 CodingKeys 声明要转成的字符串即可,如下:不需要转的就不需要写 = 后面的东西了

//
//  Person.swift
//  CustomisedViews
//
//  Created by Kyle on 2020/3/2.
//  Copyright © 2020 KyleBing. All rights reserved.
//

import Foundation

struct Person: Codable {
    var id: String
    var name: String
    var nameEn: String
    var nickName: String
    var perk: String
    var motto: String
    var health: String
    var sanity: String
    var hunger: String
    var version: String
    var pic: String
    
        enum CodingKeys: String, CodingKey {
        case nameEn = "name_en"
        case nickName = "nick_name"
        // 下面这些变量名不需要变,就只写 case 就可以了
        // 要把对象中的变量全部遍历出来,不然会出错
            case id
            case name
            case perk
            case motto
            case health
            case sanity
            case hunger
            case version
            case pic
        }
}

Android 通过 onDraw 实现在 View 中绘图操作

Android 通过 onDraw 实现在 View 中绘图操作

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >


    <LinearLayout
        android:id="@+id/layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
></LinearLayout>
</RelativeLayout>


package com.example.zidingyi;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.View;


public class DrawView extends View {
float paintX =400;
float paintY =600;
public DrawView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}


/**
* 这个方法会在初始化后背调用一次,invaildate () 的时候会被调用
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint=new Paint ();// 设置一个笔
paint.setAntiAlias (true);// 设置没有锯齿
paint.setColor (Color.RED);// 设置笔的颜色
canvas.drawCircle (paintX, paintY, 50, paint);// 距离画圆

}
}


package com.example.zidingyi;


import android.os.Bundle;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.LinearLayout;
import android.widget.Toast;


public class MainActivity extends Activity {


private LinearLayout layout;




@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        layout = (LinearLayout)  findViewById (R.id.layout);// 找到这个空间
        final DrawView drawView = new DrawView (this);// 创建自定义的控件
        drawView.setMinimumHeight(300);
        drawView.setMinimumWidth(500);
        layout.addView (drawView);// 讲自定义的控件进行添加
        // 设置一个触摸事件
        drawView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
// 改变之前的 X,Y
drawView.paintX=event.getX();
drawView.paintY=event.getY();
// 调用重新绘制
drawView.invalidate();
return true;
}
});
    }
}




Codable - 更好的使用 code 字段

Codable - 更好的使用 code 字段

ios – Swift:Codable – 提取单个编码密钥

ios – Swift:Codable – 提取单个编码密钥

我有以下代码来提取编码密钥中包含的 JSON:

let value = try! decoder.decode([String:Applmusic].self,from: $0["applmusic"])

这成功处理了以下JSON:

{
  "applmusic":{
    "code":"AAPL","quality":"good","line":"She told me don't worry",}

但是,无法使用以下代码中的applmusic编码密钥提取JSON:

{
  "applmusic":{
    "code":"AAPL",},"spotify":{
    "differentcode":"SPOT","music_quality":"good","spotify_specific_code":"absent in apple"
  },"amazon":{
    "amzncode":"SPOT","stanley":"absent in apple"
  }
}

applmusic,spotify和amazon的数据模型是不同的.但是,我只需要提取applmusic并省略其他编码密钥.

我的Swift数据模型如下:

public struct Applmusic: Codable {
    public let code: String
    public let quality: String
    public let line: String
}

API以完整的JSON响应,我不能要求它只给我所需的字段.

如何只解码json的特定部分?看来,Decodable要求我先对整个json进行反序列化,所以我必须知道它的完整数据模型.

显然,其中一个解决方案是创建一个单独的Response模型,只是为了包含applmusicparameter,但它看起来像一个hack:

public struct Response: Codable {
    public struct Applmusic: Codable {
        public let code: String
        public let quality: String
        public let line: String
    }
    // The only parameter is `applmusic`,ignoring the other parts - works fine
    public let applmusic: Applmusic
}

你能提出一个更好的方法来处理这样的JSON结构吗?

多一点洞察力

我在通用扩展中使用了以下技术,它为我自动解码API响应.因此,我更倾向于概括一种处理此类情况的方法,而无需创建根结构.如果我需要的密钥在JSON结构中是3层深度怎么办?

这是为我解码的扩展:

extension Endpoint where Response: Swift.Decodable {
  convenience init(method: Method = .get,path: Path,codingKey: String? = nil,parameters: Parameters? = nil) {
    self.init(method: method,path: path,parameters: parameters,codingKey: codingKey) {
      if let key = codingKey {
        guard let value = try decoder.decode([String:Response].self,from: $0)[key] else {
          throw RestClientError.valueNotFound(codingKey: key)
        }
        return value
      }

      return try decoder.decode(Response.self,from: $0)
    }
  }
}

API的定义如下:

extension API {
  static func getMusic() -> Endpoint<[Applmusic]> {
    return Endpoint(method: .get,path: "/api/music",codingKey: "applmusic")
  }
}

解决方法

更新:我从这个答案中扩展了JSONDecoder,您可以在这里查看它: https://github.com/aunnnn/NestedDecodable,它允许您使用键路径解码任何深度的嵌套模型.

你可以像这样使用它:

let post = try decoder.decode(Post.self,from: data,keyPath: "nested.post")

您可以创建一个Decodable包装器(例如,ModelResponse),并将所有逻辑用于提取嵌套模型,其中包含一个键:

struct DecodingHelper {

    /// Dynamic key
    private struct Key: CodingKey {
        let stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
            self.intValue = nil
        }

        let intValue: Int?
        init?(intValue: Int) {
            return nil
        }
    }

    /// Dummy model that handles model extracting logic from a key
    private struct ModelResponse<nestedModel: Decodable>: Decodable {
        let nested: nestedModel

        public init(from decoder: Decoder) throws {
            let key = Key(stringValue: decoder.userInfo[CodingUserInfoKey(rawValue: "my_model_key")!]! as! String)!
            let values = try decoder.container(keyedBy: Key.self)
            nested = try values.decode(nestedModel.self,forKey: key)
        }
    }

    static func decode<T: Decodable>(modelType: T.Type,fromKey key: String) throws -> T {
        // mock data,replace with network response
        let path = Bundle.main.path(forResource: "test",ofType: "json")!
        let data = try Data(contentsOf: URL(fileURLWithPath: path),options: .mappedIfSafe)

        let decoder = JSONDecoder()

        // ***Pass in our key through `userInfo`
        decoder.userInfo[CodingUserInfoKey(rawValue: "my_model_key")!] = key
        let model = try decoder.decode(ModelResponse<T>.self,from: data).nested
        return model
    }
}

您可以通过JSONDecoder的userInfo(“my_model_key”)传递所需的密钥.然后将其转换为ModelResponse中的动态Key以实际提取模型.

然后你可以像这样使用它:

let appl = try DecodingHelper.decode(modelType: Applmusic.self,fromKey: "applmusic")
let amazon = try DecodingHelper.decode(modelType: Amazon.self,fromKey: "amazon")
let spotify = try DecodingHelper.decode(modelType: Spotify.self,fromKey: "spotify")
print(appl,amazon,spotify)

完整代码:
https://gist.github.com/aunnnn/2d6bb20b9dfab41189a2411247d04904

额外奖励:深层嵌套密钥

在玩了更多之后,我发现你可以使用这个修改过的ModelResponse轻松解码任意深度的键:

private struct ModelResponse<nestedModel: Decodable>: Decodable {
    let nested: nestedModel

    public init(from decoder: Decoder) throws {
        // Split nested paths with '.'
        var keypaths = (decoder.userInfo[CodingUserInfoKey(rawValue: "my_model_key")!]! as! String).split(separator: ".")

        // Get last key to extract in the end
        let lastKey = String(keypaths.popLast()!)

        // Loop getting container until reach final one
        var targetContainer = try decoder.container(keyedBy: Key.self)
        for k in keypaths {
            let key = Key(stringValue: String(k))!
            targetContainer = try targetContainer.nestedContainer(keyedBy: Key.self,forKey: key)
        }
        nested = try targetContainer.decode(nestedModel.self,forKey: Key(stringValue: lastKey)!)
    }

然后你可以像这样使用它:

let deeplynestedModel = try DecodingHelper.decode(modelType: Amazon.self,fromKey: "nest1.nest2.nest3")

从这个json:

{
    "apple": { ... },"amazon": {
        "amzncode": "SPOT","music_quality": "good","stanley": "absent in apple"
    },"nest1": {
        "nest2": {
            "amzncode": "nest works","music_quality": "Great","stanley": "Oh yes","nest3": {
                "amzncode": "nest works,again!!!","stanley": "Oh yes"
            }
        }
    }
}

完整代码:https://gist.github.com/aunnnn/9a6b4608ae49fe1594dbcabd9e607834

java 集成 pageoffice 实现在 word 中插入表格并赋值

java 集成 pageoffice 实现在 word 中插入表格并赋值

Word中的table操作需要借助数据区域(DataRegion)实现的,要求数据区域完整的包含了整个Table的内容,这样才可以通过数据区域控制和操作table。因此,要想使用table,则必须在word文件中插入书签。而table的插入,既可以在Word模版中书签处手动插入:工具栏“插入”→“表格”,亦可以在程序中通过数据区域动态添加。

下面介绍一下动态添加表格的具体步骤

1:给Word模板中创建一个书签。(两种方法)

(1)可以在word 模板中手动添加一个书签:工具栏“插入”→“书签”

 

(2)用 pageoffice 动态创建一个数据区域(书签)

2:插入表格

2:具体的代码

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%@ page
	import="com.zhuozhengsoft.pageoffice.*,com.zhuozhengsoft.pageoffice.wordwriter.*"%>
<%
	PageOfficeCtrl poCtrl = new PageOfficeCtrl(request);
	WordDocument doc = new WordDocument();
	//在word中指定的"PO_table1"的数据区域内动态创建一个3行5列的表格
	Table table1 = doc.openDataRegion("PO_table").createTable(3,5,WdAutoFitBehavior.wdAutoFitWindow);
	//合并(1,1)到(3,1)的单元格并赋值
        table1.openCellRC(1,1).mergeTo(3,1);
        table1.openCellRC(1,1).setValue("合并后的单元格");
	//给表格table1中剩余的单元格赋值
	for(int i=1;i<4;i++){
	    table1.openCellRC(i, 2).setValue("AA" + String.valueOf(i));
            table1.openCellRC(i, 3).setValue("BB" + String.valueOf(i));
            table1.openCellRC(i, 4).setValue("CC" + String.valueOf(i));
	    table1.openCellRC(i, 5).setValue("DD" + String.valueOf(i));
	}
	
	//在"PO_table1"后面动态创建一个新的数据区域"PO_table2",用于创建新的一个5行5列的表格table2
	DataRegion drTable2= doc.createDataRegion("PO_table2", DataRegionInsertType.After, "PO_table1");
	Table table2=drTable2.createTable(5,5,WdAutoFitBehavior.wdAutoFitWindow);
	//给新表格table2赋值
	for(int i=1;i<6;i++){
	    table2.openCellRC(i, 1).setValue("AA" + String.valueOf(i));
	    table2.openCellRC(i, 2).setValue("BB" + String.valueOf(i));
            table2.openCellRC(i, 3).setValue("CC" + String.valueOf(i));
            table2.openCellRC(i, 4).setValue("DD" + String.valueOf(i));
	    table2.openCellRC(i, 5).setValue("EE" + String.valueOf(i));
	}
	
	poCtrl.setWriter(doc);//此行必须
	poCtrl.setServerPage(request.getContextPath()+"/poserver.zz");
	poCtrl.webOpen("doc/createTable.doc", OpenModeType.docNormalEdit,"张佚名");
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
	<head>

		<title>Word中动态创建表格</title>
		

	</head>

	<body>
		<div>
			  <%=poCtrl.getHtmlCode("PageOfficeCtrl1")%>
		</div>
	</body>
</html>

最终效果

大家可以去pageoffice官网下载示例代码直接将samples4文件夹扔到Tomcat的webapps下,启动Tomcat,浏览器访问。

刚开始接触pageoffice的话,也可以看视频快速上手http://www.zhuozhengsoft.com/Technical/

 

关于Codable: 实现在 swift 中像 js 那样使用 JSONcodice swift的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于Android 通过 onDraw 实现在 View 中绘图操作、Codable - 更好的使用 code 字段、ios – Swift:Codable – 提取单个编码密钥、java 集成 pageoffice 实现在 word 中插入表格并赋值的相关信息,请在本站寻找。

本文标签: