GVKun编程网logo

Swift 4 Codable-Bool或String值(swift rangeofstring)

9

在本文中,我们将为您详细介绍Swift4Codable-Bool或String值的相关知识,并且为您解答关于swiftrangeofstring的疑问,此外,我们还会提供一些关于com.faceboo

在本文中,我们将为您详细介绍Swift 4 Codable-Bool或String值的相关知识,并且为您解答关于swift rangeofstring的疑问,此外,我们还会提供一些关于com.facebook.swift.codec.ThriftConstructor的实例源码、iOS swift NSMutableData没有成员appendString、ios – Swift:Codable – 提取单个编码密钥、iOS – 如何在swift中使用`NSMutableString`的有用信息。

本文目录一览:

Swift 4 Codable-Bool或String值(swift rangeofstring)

Swift 4 Codable-Bool或String值(swift rangeofstring)

寻找一些有关如何处理我最近遇到的情况的意见。

我一直在使用Swift 4s Codable取得成功,但今天发现了我没有想到的崩溃。我正在使用的API说,它boolean为key 返回a
manage_stock

我的存根结构如下:

struct Product: Codable {    var manage_stock: Bool?}

效果很好,问题在于API 有时会 返回a string而不是a boolean

因此,我的解码失败并显示:

Expected to decode Bool but found a string/data instead.

该字符串只能等于"parent",我希望它等于false

我也可以将结构更改为var manage_stock:String?是否可以简化从API导入JSON数据的过程。但是,当然,如果我更改了此设置,我的错误将变为:

Expected to decode String but found a number instead.

有没有一种简单的方法来处理这种突变,或者我需要失去所有Codable带来表的自动化并实现我自己的自动化init(decoder: Decoder)

干杯

答案1

小编典典

由于您无法始终控制要使用的API,因此这是一种Codable通过重写直接解决此问题的简单方法init(from:)

struct Product : Decodable {    // Properties in Swift are camelCased. You can provide the key separately from the property.    var manageStock: Bool?    private enum CodingKeys : String, CodingKey {        case manageStock = "manage_stock"    }    init(from decoder: Decoder) throws {        let container = try decoder.container(keyedBy: CodingKeys.self)        do {            self.manageStock = try container.decodeIfPresent(Bool.self, forKey: .manageStock)        } catch DecodingError.typeMismatch {            // There was something for the "manage_stock" key, but it wasn''t a boolean value. Try a string.            if let string = try container.decodeIfPresent(String.self, forKey: .manageStock) {                // Can check for "parent" specifically if you want.                self.manageStock = false            }        }    }}

有关更多信息,请参见编码和解码自定义类型。

com.facebook.swift.codec.ThriftConstructor的实例源码

com.facebook.swift.codec.ThriftConstructor的实例源码

项目:hadoop-EAR    文件:HdfsFileStatus.java   
/**
 * Constructor
 * @param length the number of bytes the file has
 * @param isdir if the path is a directory
 * @param block_replication the replication factor
 * @param blocksize the block size
 * @param modification_time modification time
 * @param access_time access time
 * @param permission permission
 * @param owner the owner of the path
 * @param group the group of the path
 * @param path the local name in java UTF8 encoding the same as that in-memory
 */
@ThriftConstructor
public HdfsFileStatus(@ThriftField(1) long length,@ThriftField(2) boolean isdir,@ThriftField(3) int block_replication,@ThriftField(4) long blocksize,@ThriftField(5) long modification_time,@ThriftField(6) long access_time,@ThriftField(7) FsPermission permission,@ThriftField(8) String owner,@ThriftField(9) String group,@ThriftField(10) byte[] path) {
  this.length = length;
  this.isdir = isdir;
  this.block_replication = (short)block_replication;
  this.blocksize = blocksize;
  this.modification_time = modification_time;
  this.access_time = access_time;
  this.permission = (permission == null) ? 
                    FsPermission.getDefault() : permission;
  this.owner = (owner == null) ? "" : owner;
  this.group = (group == null) ? "" : group;
  this.path = path;
}
项目:hadoop-EAR    文件:DatanodeInfo.java   
@ThriftConstructor
// Last ThriftField used in superclass: 4
public DatanodeInfo(@ThriftField(1) String name,@ThriftField(2) String storageID,@ThriftField(3) int infoPort,@ThriftField(4) int ipcPort,@ThriftField(6) long capacity,@ThriftField(7) long dfsUsed,@ThriftField(8) long remaining,@ThriftField(9) long namespaceUsed,@ThriftField(10) long lastUpdate,@ThriftField(11) int xceiverCount,@ThriftField(12) String networkLocation,@ThriftField(13) String hostName,@ThriftField(14) int adminStateOrdinal) {
  super(name,storageID,infoPort,ipcPort);
  this.capacity = capacity;
  this.dfsUsed = dfsUsed;
  this.remaining = remaining;
  this.namespaceUsed = namespaceUsed;
  this.lastUpdate = lastUpdate;
  this.xceiverCount = xceiverCount;
  this.location = networkLocation;
  this.hostName = hostName;
  setAdminState(AdminStates.values()[adminStateOrdinal]);
}
项目:swift-hive-metastore    文件:Index.java   
@ThriftConstructor
public Index(
             @ThriftField(value = 1,name = "indexName") final String indexName,@ThriftField(value = 2,name = "indexHandlerClass") final String indexHandlerClass,@ThriftField(value = 3,name = "dbname") final String dbname,@ThriftField(value = 4,name = "origTableName") final String origTableName,@ThriftField(value = 5,name = "createTime") final int createTime,@ThriftField(value = 6,name = "lastAccesstime") final int lastAccesstime,@ThriftField(value = 7,name = "indexTableName") final String indexTableName,@ThriftField(value = 8,name = "sd") final StorageDescriptor sd,@ThriftField(value = 9,name = "parameters") final Map<String,String> parameters,@ThriftField(value = 10,name = "deferredRebuild") final boolean deferredRebuild)
{
    this.indexName = indexName;
    this.indexHandlerClass = indexHandlerClass;
    this.dbname = dbname;
    this.origTableName = origTableName;
    this.createTime = createTime;
    this.lastAccesstime = lastAccesstime;
    this.indexTableName = indexTableName;
    this.sd = sd;
    this.parameters = parameters;
    this.deferredRebuild = deferredRebuild;
}
项目:swift-hive-metastore    文件:Partition.java   
@ThriftConstructor
public Partition(
                 @ThriftField(value = 1,name = "values") final List<String> values,name = "tableName") final String tableName,name = "privileges") final PrincipalPrivilegeSet privileges,name = "linkTarget") final PartitionIdentifier linkTarget,name = "linkPartitions") final List<PartitionIdentifier> linkPartitions)
{
    this.values = values;
    this.dbname = dbname;
    this.tableName = tableName;
    this.createTime = createTime;
    this.lastAccesstime = lastAccesstime;
    this.sd = sd;
    this.parameters = parameters;
    this.privileges = privileges;
    this.linkTarget = linkTarget;
    this.linkPartitions = linkPartitions;
}
项目:hadoop-EAR    文件:ContentSummary.java   
/** Constructor */
@ThriftConstructor
public ContentSummary(
    @ThriftField(1) long length,@ThriftField(2) long fileCount,@ThriftField(3) long directoryCount,@ThriftField(4) long quota,@ThriftField(5) long spaceConsumed,@ThriftField(6) long spaceQuota) {
  this.length = length;
  this.fileCount = fileCount;
  this.directoryCount = directoryCount;
  this.quota = quota;
  this.spaceConsumed = spaceConsumed;
  this.spaceQuota = spaceQuota;
}
项目:hadoop-EAR    文件:DatanodeID.java   
/**
 * Create DatanodeID
 * @param name (hostname:portNumber)
 * @param storageID data storage ID
 * @param infoPort info server port 
 * @param ipcPort ipc server port
 */
@ThriftConstructor
public DatanodeID(@ThriftField(1) String name,@ThriftField(4) int ipcPort) {
  this.name = name;
  this.storageID = storageID;
  this.infoPort = infoPort;
  this.ipcPort = ipcPort;
}
项目:hadoop-EAR    文件:VersionedLocatedBlock.java   
@ThriftConstructor
public VersionedLocatedBlock(@ThriftField(1) Block block,@ThriftField(2) List<DatanodeInfo> datanodes,@ThriftField(3) long startOffset,@ThriftField(4) boolean corrupt,@ThriftField(5) int dataProtocolVersion) {
  super(block,datanodes,startOffset,corrupt);
  this.dataProtocolVersion = dataProtocolVersion;
}
项目:hadoop-EAR    文件:LocatedBlocks.java   
@ThriftConstructor
public LocatedBlocks(@ThriftField(1) long fileLength,@ThriftField(2) List<LocatedBlock> locatedBlocks,@ThriftField(3) boolean isUnderConstuction) {
  this.fileLength = fileLength;
  blocks = locatedBlocks;
  underConstruction = isUnderConstuction;
}
项目:hadoop-EAR    文件:LocatedBlockWithMetaInfo.java   
@ThriftConstructor
public LocatedBlockWithMetaInfo(@ThriftField(1) Block block,@ThriftField(5) int dataProtocolVersion,@ThriftField(6) int namespaceId,@ThriftField(7) int methodFingerPrint) {
  super(block,corrupt,dataProtocolVersion);
  this.namespaceid = namespaceId;
  this.methodFingerPrint = methodFingerPrint;
}
项目:hadoop-EAR    文件:LocatedBlockWithFileName.java   
@ThriftConstructor
public LocatedBlockWithFileName(@ThriftField(1) Block block,@ThriftField(5) String fileName) {
  super(block,corrupt);
  this.fullPath = fileName;
}
项目:hadoop-EAR    文件:LocatedBlocksWithMetaInfo.java   
@ThriftConstructor
public LocatedBlocksWithMetaInfo(@ThriftField(1) long fileLength,@ThriftField(3) boolean isUnderConstuction,@ThriftField(4) int dataProtocolVersion,@ThriftField(5) int namespaceId,@ThriftField(6) int methodFingerPrint) {
  super(fileLength,locatedBlocks,isUnderConstuction,dataProtocolVersion);
  this.namespaceid = namespaceId;
  this.methodFingerPrint = methodFingerPrint;
}
项目:hadoop-EAR    文件:LocatedBlockWithOldGS.java   
@ThriftConstructor
public LocatedBlockWithOldGS(@ThriftField(1) Block block,@ThriftField(7) int methodFingerPrint,@ThriftField(8) long oldGenerationStamp) {
  super(block,dataProtocolVersion,namespaceId,methodFingerPrint);
  this.oldGenerationStamp = oldGenerationStamp;
}
项目:hadoop-EAR    文件:VersionedLocatedBlocks.java   
@ThriftConstructor
public VersionedLocatedBlocks(@ThriftField(1) long fileLength,@ThriftField(4) int dataProtocolVersion) {
  super(fileLength,isUnderConstuction);
  this.dataProtocolVersion = dataProtocolVersion;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public RequestMetaInfo(int clusterId,String resourceId,int namespaceId,int applicationId,UnixUserGroupinformation origCaller) {
  this.clusterId = clusterId;
  this.resourceId = resourceId;
  this.namespaceId = namespaceId;
  this.applicationId = applicationId;
  this.origCaller = origCaller;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public GetBlockLocationsRequest(@ThriftField(1) RequestMetaInfo requestMetaInfo,@ThriftField(2) String src,@ThriftField(3) long offset,@ThriftField(4) long length) {
  super(requestMetaInfo,src);
  this.offset = offset;
  this.length = length;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public OpenRequest(@ThriftField(1) RequestMetaInfo requestMetaInfo,src);
  this.offset = offset;
  this.length = length;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public CreateRequest(@ThriftField(1) RequestMetaInfo requestMetaInfo,@ThriftField(3) String clientName,@ThriftField(4) @NotNull FsPermission masked,@ThriftField(5) boolean overwrite,@ThriftField(6) boolean createParent,@ThriftField(7) short replication,@ThriftField(8) long blockSize) {
  super(requestMetaInfo,src,clientName);
  notNull(masked);
  this.masked = masked;
  this.overwrite = overwrite;
  this.createParent = createParent;
  this.replication = replication;
  this.blockSize = blockSize;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public CloseRecoverLeaseRequest(@ThriftField(1) RequestMetaInfo requestMetaInfo,@ThriftField(4) boolean discardLastBlock) {
  super(requestMetaInfo,clientName);
  this.discardLastBlock = discardLastBlock;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public SetPermissionRequest(@ThriftField(1) RequestMetaInfo requestMetaInfo,@ThriftField(3) @NotNull FsPermission permission) {
  super(requestMetaInfo,src);
  notNull(permission);
  this.permission = permission;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public SetownerRequest(@ThriftField(1) RequestMetaInfo requestMetaInfo,@ThriftField(3) String username,@ThriftField(4) String groupname) {
  super(requestMetaInfo,src);
  this.username = username;
  this.groupname = groupname;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public AbandonBlockRequest(@ThriftField(1) RequestMetaInfo requestMetaInfo,@ThriftField(4) Block block) {
  super(requestMetaInfo,clientName);
  this.block = block;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public AddBlockRequest(RequestMetaInfo requestMetaInfo,String src,String clientName,List<DatanodeInfo> excludednodes,List<DatanodeInfo> favorednodes,long startPos,Block lastBlock) {
  super(requestMetaInfo,clientName);
  this.excludednodes = excludednodes;
  this.favorednodes = favorednodes;
  this.startPos = startPos;
  this.lastBlock = lastBlock;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public CompleteRequest(RequestMetaInfo requestMetaInfo,long fileLen,clientName);
  this.fileLen = fileLen;
  this.lastBlock = lastBlock;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public ConcatRequest(RequestMetaInfo requestMetaInfo,String trg,List<String> srcs,boolean restricted) {
  super(requestMetaInfo);
  this.trg = trg;
  this.srcs = srcs;
  this.restricted = restricted;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public MkdirsRequest(RequestMetaInfo requestMetaInfo,@NotNull FsPermission masked) {
  super(requestMetaInfo,src);
  notNull(masked);
  this.masked = masked;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public IterativeGetopenFilesRequest(RequestMetaInfo requestMetaInfo,int millis,String start) {
  super(requestMetaInfo,src);
  this.millis = millis;
  this.start = start;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public UpdatePipelineRequest(RequestMetaInfo requestMetaInfo,Block oldBlock,Block newBlock,List<DatanodeID> newNodes) {
  super(requestMetaInfo,clientName);
  this.oldBlock = oldBlock;
  this.newBlock = newBlock;
  this.newNodes = newNodes;
}
项目:hadoop-EAR    文件:ClientProxyRequests.java   
@ThriftConstructor
public RaidFileRequest(RequestMetaInfo requestMetaInfo,String codecId,short expectedSourceReplication) {
  super(requestMetaInfo,src);
  this.codecId = codecId;
  this.expectedSourceReplication = expectedSourceReplication;
}
项目:mandrel    文件:PageRequest.java   
/**
 * Creates a new {@link PageRequest}. Pages are zero indexed,thus providing 0 for {@code page} will return
 * the first page.
 * 
 * @param page
 *            must not be less than zero.
 * @param size
 *            must not be less than one.
 */
@ThriftConstructor
public PageRequest(@ThriftField(value = 1,name = "pageNumber") int page,name = "pageSize") int size) {

    if (page < 0) {
        throw new IllegalArgumentException("Page index must not be less than zero!");
    }

    if (size < 1) {
        throw new IllegalArgumentException("Page size must not be less than one!");
    }

    this.pageNumber = page;
    this.pageSize = size;
}
项目:thrift-swift-finagle-example    文件:ValidationException.java   
@ThriftConstructor
public ValidationException(int errorCode,String field,String message) {
    super(message);
    this.errorCode = errorCode;
    this.message = message;
    this.field = field;
}
项目:swift-hive-metastore    文件:StorageDescriptor.java   
@ThriftConstructor
public StorageDescriptor(
                         @ThriftField(value = 1,name = "cols") final List<FieldSchema> cols,name = "location") final String location,name = "inputFormat") final String inputFormat,name = "outputFormat") final String outputFormat,name = "compressed") final boolean compressed,name = "numBuckets") final int numBuckets,name = "serdeInfo") final SerDeInfo serdeInfo,name = "bucketCols") final List<String> bucketCols,name = "sortCols") final List<Order> sortCols,@ThriftField(value = 11,name = "skewedInfo") final SkewedInfo skewedInfo,@ThriftField(value = 12,name = "storedAsSubDirectories") final boolean storedAsSubDirectories,@ThriftField(value = 13,name = "statsFresh") final boolean statsFresh)
{
    this.cols = cols;
    this.location = location;
    this.inputFormat = inputFormat;
    this.outputFormat = outputFormat;
    this.compressed = compressed;
    this.numBuckets = numBuckets;
    this.serdeInfo = serdeInfo;
    this.bucketCols = bucketCols;
    this.sortCols = sortCols;
    this.parameters = parameters;
    this.skewedInfo = skewedInfo;
    this.storedAsSubDirectories = storedAsSubDirectories;
    this.statsFresh = statsFresh;
}
项目:swift-hive-metastore    文件:PartitionIdentifier.java   
@ThriftConstructor
public PartitionIdentifier(
                           @ThriftField(value = 1,name = "values") final List<String> values)
{
    this.dbname = dbname;
    this.tableName = tableName;
    this.values = values;
}
项目:swift-hive-metastore    文件:Order.java   
@ThriftConstructor
public Order(
             @ThriftField(value = 1,name = "col") final String col,name = "order") final int order)
{
    this.col = col;
    this.order = order;
}
项目:swift-hive-metastore    文件:ColumnStatistics.java   
@ThriftConstructor
public ColumnStatistics(
                        @ThriftField(value = 1,name = "statsDesc") final ColumnStatisticsDesc statsDesc,name = "statsObj") final List<ColumnStatisticsObj> statsObj)
{
    this.statsDesc = statsDesc;
    this.statsObj = statsObj;
}
项目:swift-hive-metastore    文件:BooleanColumnStatsData.java   
@ThriftConstructor
public BooleanColumnStatsData(
                              @ThriftField(value = 1,name = "numTrues") final long numTrues,name = "numFalses") final long numFalses,name = "numNulls") final long numNulls)
{
    this.numTrues = numTrues;
    this.numFalses = numFalses;
    this.numNulls = numNulls;
}
项目:swift-hive-metastore    文件:BinaryColumnStatsData.java   
@ThriftConstructor
public BinaryColumnStatsData(
                             @ThriftField(value = 1,name = "maxColLen") final long maxColLen,name = "avgColLen") final double avgColLen,name = "numNulls") final long numNulls)
{
    this.maxColLen = maxColLen;
    this.avgColLen = avgColLen;
    this.numNulls = numNulls;
}
项目:swift-hive-metastore    文件:DoubleColumnStatsData.java   
@ThriftConstructor
public DoubleColumnStatsData(
                             @ThriftField(value = 1,name = "lowValue") final double lowValue,name = "highValue") final double highValue,name = "numNulls") final long numNulls,name = "numDVs") final long numDVs)
{
    this.lowValue = lowValue;
    this.highValue = highValue;
    this.numNulls = numNulls;
    this.numDVs = numDVs;
}
项目:swift-hive-metastore    文件:Version.java   
@ThriftConstructor
public Version(
               @ThriftField(value = 1,name = "version") final String version,name = "comments") final String comments)
{
    this.version = version;
    this.comments = comments;
}
项目:swift-hive-metastore    文件:HiveObjectPrivilege.java   
@ThriftConstructor
public HiveObjectPrivilege(
                           @ThriftField(value = 1,name = "hiveObject") final HiveObjectRef hiveObject,name = "principalName") final String principalName,name = "principalType") final PrincipalType principalType,name = "grantInfo") final PrivilegeGrantInfo grantInfo)
{
    this.hiveObject = hiveObject;
    this.principalName = principalName;
    this.principalType = principalType;
    this.grantInfo = grantInfo;
}
项目:swift-hive-metastore    文件:ColumnStatisticsData.java   
@ThriftConstructor
public ColumnStatisticsData(final BooleanColumnStatsData booleanStats)
{
    this.value = booleanStats;
    this.id = 1;
    this.name = "booleanStats";
}

iOS swift NSMutableData没有成员appendString

iOS swift NSMutableData没有成员appendString

您好我是 swift的新手,我正在按照教程和创建相同的代码来上传图像.我现在使用的是swift 3,看起来NSMutableData()似乎不再有appendString方法可以作为替代品做什么?我关注的教程是 http://swiftdeveloperblog.com/image-upload-example/,我的代码就是这个
func createBodyWithParameters(parameters: [String: String]?,filePathKey: String?,imageDataKey: NSData,boundary: String) -> NSData {
       let body = NSMutableData()

        if parameters != nil {
            for (key,value) in parameters! {
                body.("--\(boundary)\r\n")
                body.appendString("Content-disposition: form-data; name=\"\(key)\"\r\n\r\n")
                body.appendString("\(value)\r\n")
            }
        }

        let filename = "user-profile.jpg"
        let mimetype = "image/jpg"

        body.appendString(options: <#T##NSData.Base64EncodingOptions#>)("--\(boundary)\r\n")
        body.appendString("Content-disposition: form-data; name=\"\(filePathKey!)\"; filename=\"\(filename)\"\r\n")
        body.appendString("Content-Type: \(mimetype)\r\n\r\n")
        body.appendString("\r\n")



        body.appendString("--\(boundary)--\r\n")

        return body
    }

问题再次出现在appendString中,因为我收到错误:

NSMutableData类型的值没有成员appendString

我一直在寻找周围的工作,但没有找到任何,我有可用的追加方法,但它不需要一个字符串.

解决方法

正如@dan在评论中指出的那样,该方法是您正在研究的教程的一部分.不过,在Swift中很容易定义自定义方法.

首先,不要使用NSMutableData;相反,使用新的Data结构,根据您是使用var还是let,它将是可变的或不可变的:

var body = Data()

然后追加UTF-8字节:

body.append(Data("foo".utf8))

(如果你需要UTF-8以外的东西,还有其他编码的String方法.)

如果你想要教程的确切行为,这里是如何将其方法转换为Swift 3:

extension Data {
  mutating func append(string: String) {
    let data = string.data(
        using: String.Encoding.utf8,allowLossyConversion: true)
    append(data!)
  }
}

…

body.append("foo")

但是,我不建议使用此代码,原因有两个.首先,有损转换意味着您的应用可能会默默地丢弃重要数据.其次,强制解包(数据!而不是数据)意味着如果编码出现问题,您的应用程序将崩溃而不是显示有用的错误.

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

iOS – 如何在swift中使用`NSMutableString`

iOS – 如何在swift中使用`NSMutableString`

我已经看过这个Objective-C代码,但我很难在 swift中做同样的事情:

NSMutableAttributedString *res = [self.richTextEditor.attributedText mutablecopy];

[res beginEditing];
__block BOOL found = NO;
[res enumerateAttribute:NSFontAttributeName inRange:NSMakeRange(0,res.length) options:0 usingBlock:^(id value,NSRange range,BOOL *stop) {
    if (value) {
        UIFont *oldFont = (UIFont *)value;
        UIFont *newFont = [oldFont fontWithSize:oldFont.pointSize * 2];
        [res removeAttribute:NSFontAttributeName range:range];
        [res addAttribute:NSFontAttributeName value:newFont range:range];
        found = YES;
    }
}];
if (!found) {
    // No font was found - do something else?
}
[res endEditing];
self.richTextEditor.attributedText = res;

我试图通过迭代每个属性来更改NSMutableAttributedString中的字体.我很高兴听到有更好的方法,但如果有人能帮助我翻译上述内容,我会感到非常满意.

解决方法

这是一个基本的实现.这对我来说似乎很简单,你没有提供你的尝试,所以我不确定你是否有类似的东西,它有问题,或者如果你刚刚接触Swift.

一个区别是这个实现使用可选的转换(如?),我这样做是为了演示这个概念.实际上,这不需要是可选的,因为NSFontAttributeName保证提供UIFont.

var res : NSMutableAttributedString = NSMutableAttributedString(string: "test");

res.beginEditing()

var found = false

res.enumerateAttribute(NSFontAttributeName,inRange: NSMakeRange(0,res.length),options: NSAttributedStringEnumerationoptions(0)) { (value,range,stop) -> Void in
    if let oldFont = value as? UIFont {
        let newFont = oldFont.fontWithSize(oldFont.pointSize * 2)
        res.removeAttribute(NSFontAttributeName,range: range)
        res.addAttribute(NSFontAttributeName,value: newFont,range: range)
        found = true
    }
}

if found == false {

}

res.endEditing()

关于Swift 4 Codable-Bool或String值swift rangeofstring的介绍已经告一段落,感谢您的耐心阅读,如果想了解更多关于com.facebook.swift.codec.ThriftConstructor的实例源码、iOS swift NSMutableData没有成员appendString、ios – Swift:Codable – 提取单个编码密钥、iOS – 如何在swift中使用`NSMutableString`的相关信息,请在本站寻找。

本文标签: