Objective-C 和 NSCoding 原始数据类型,就像旧的 C 代码一样

Posted

技术标签:

【中文标题】Objective-C 和 NSCoding 原始数据类型,就像旧的 C 代码一样【英文标题】:Objective-C and NSCoding primative data type just like the old C code 【发布时间】:2012-09-17 20:45:31 【问题描述】:

我有一些看起来像这样的旧 C 代码:

#include <stdio.h>
#include <strings.h>
main()


    FILE *output;

    struct socket_cpacket
    
        char    type;                                /* CP_SOCKET */
        char    version;
        char    udp_version;                         /* was pad2 */
        char    pad3;
        unsigned socket;
    ;

    struct socket_cpacket sockPack;

    bzero(&sockPack,sizeof(sockPack));
    sockPack.type = 27;
    sockPack.version = 4;
    sockPack.udp_version = 10;
    sockPack.pad3 = 0;
    sockPack.socket = 0;

    output = fopen("/tmp/sockPack.bin", "wb");
    fwrite(&sockPack, sizeof(sockPack), 1, output);

我想在 obj-c 中复制此功能,并开始使用 NSCoding 协议。

CP_Socket.h

#import <Foundation/Foundation.h>

@interface CP_Socket : NSObject <NSCoding>

@private
    char type;
    char version;
    char udp_version;
    char pad3;
    unsigned int socket;


@property (readonly) char type;
@property (readonly) char version;
@property (readonly) char udp_version;
@property (readonly) char pad3;
@property unsigned int socket;

typedef enum 
    mTYPE = 27,
    mVERSION = 4,
    mUDP_VERSION = 10,
 cpSocketEnum;

@end

还有 CP_Socket.m

#import "CP_Socket.h"

@implementation CP_Socket

#pragma mark ======== properties =========

@synthesize  type;
@synthesize  version;
@synthesize  udp_version;
@synthesize  pad3;
@synthesize  socket;


- (id)init 
    NSLog(@"init");

    if( !( self = [super init] ) )
        return nil;

    type = mTYPE;
    version = mVERSION;
    udp_version = mUDP_VERSION;
    pad3 = 0;
    socket = 0;

    return self;


#pragma mark ======== Archiving and unarchiving methods =========
//
// Archives and Serializations Programming Guide for Cocoa
// http://bit.ly/PAaRsV
//
// NSCoding Protocol Reference
// http://bit.ly/PAb1Rd
//

- (void)encodeWithCoder:(NSCoder *)coder

    NSLog(@"encodeWithCoder");

    [coder encodeBytes:[self type] length:1 forKey:@"type"];
    //[coder encodeBytes:[self version] length:1 forKey:@"version"];
    //[coder encodeBytes:[self udp_version] length:1 forKey:@"udp_version"];
    //[coder encodeBytes:[self pad3] length:1 forKey:@"pad3"];
    //[coder encodeInt:[self socket] forKey:@"socket"];



- (id)initWithCoder:(NSCoder *)coder

    NSLog(@"initWithCoder");

@end

第一个问题,[coder encodeBytes:[self type] length:1 forKey:@"type"];发出警告。不兼容的整数到指针转换将“char”发送到“const uint8_t *”类型的参数。

如何对字符进行编码?

我试过 [coder encodeInt:[self type] forKey:@"type"];但是字符!= int。

阅读代码以进一步了解其工作原理; obj-c 代码生成的文件是 280 字节,查看文件内部我看到看起来像名称损坏的类标识符。

我尝试过 NSKeyedArchiver 和 NSArchiver,结果相同。

我不知道从这里去哪里。 C 代码生成一个 8 字节的文件。我希望 obj-c 代码在使用 NSCoding 协议等一些面向对象的东西时执行相同的操作。

我觉得我必须扩展 NSCoder 对象才能完成这项工作。

任何帮助将不胜感激。

【问题讨论】:

"如何编码一个字符?"传递一个指向它的指针。 char c = [self type]; [coder encodeBytes:&amp;c length:1 forKey:@"type"]; 抛出警告:发送“char *”到“const uint8_t *”(又名“const unsigned char *”)类型的参数会在点之间转换为具有不同符号的整数类型 或无符号字符,或其他。这个警告并不可怕。 【参考方案1】:

encodeBytes:length:forKey: 的第一个参数应该是指向要编码的缓冲区的指针,因此请获取 ivar 的地址:

[coder encodeBytes:&type length:1 forKey:@"type"];

或者创建一个临时变量,将属性访问的结果放入其中,并获取其地址。

使用 encodeInt:forKey: 也应该可以(使用演员表),但它会增加数据文件的大小。

如果你真的想要,你当然可以用一个类别扩展NSCoder

@implementation NSCoder (BTEncodeChar)
- (void)BTencodeChar: (char)c forKey: (NSString *)key

    [self encodeBytes:&c length:1 forKey:key];

@end

【讨论】:

消耗这个文件的是一个 8 字节的文件。如果文件的内容与旧的 C 代码 struct->disk write 不同,则数据的使用者将忽略它。【参考方案2】:

我对 NSCoding 了解不多,但 obj C 与 C 互操作就好了。将您现有的代码放入带有参数的函数中并调用它。

【讨论】:

最终可能会发生这种情况。但我想了解更多关于 obj-c 如何实现 NSCoding 协议以及如何覆盖事物以获得所需结果的更多信息。

以上是关于Objective-C 和 NSCoding 原始数据类型,就像旧的 C 代码一样的主要内容,如果未能解决你的问题,请参考以下文章

Objective-C数据保存和读取

如何在 Objective-C 中保存另一个类正在使用的类对象?

Objective-c 保存原始文本

在objective-c中为原始类型分配内存的最佳实践

iphone opengl es 2.0,如何使用objective-c类来存储原始数据?

在 iOS 上使用 Parse BaaS:我应该使用 PFFile 来保存原始类型和 Objective-C 类吗?