运维开发网

有没有办法将协议缓冲区包装到Objective-C中并仍然利用继承?

运维开发网 https://www.qedev.com 2020-05-19 19:39 出处:网络 作者:运维开发网整理
我想在iOS项目中使用Protocol Buffers.我试图避免将整个项目变成Objective-C惨败,所以我想将C protobuf类包装成Objective-C类.我有几十个protobuf消息,虽然我一次成功地完成了一个类,但理想情况下我想使用继承来最小化重复的代码.我是Objective-C的新手,我在10年内没有使用过我对C的了解,所以这主要是一种挫败感.下面是我如何包装单个邮件的示
我想在iOS项目中使用Protocol Buffers.我试图避免将整个项目变成Objective-C惨败,所以我想将C protobuf类包装成Objective-C类.我有几十个protobuf消息,虽然我一次成功地完成了一个类,但理想情况下我想使用继承来最小化重复的代码.我是Objective-C的新手,我在10年内没有使用过我对C的了解,所以这主要是一种挫败感.下面是我如何包装单个邮件的示例.

.proto:

message MessageA {
    optional string value = 1;
}

MessageAWrapper.h:

#import <Foundation/Foundation.h>

@interface MessageAWrapper : NSObject

@property (nonatomic) NSString *value;

+ (id)fromString:(NSString *)string;
- (NSString *)serialize;

@end

MessageAWrapper.mm:

#import "MessageA.h"
#import "message.pb.h"

@interface MessageAWrapper ()

@property (nonatomic) MessageA *message;

@end

@implementation MessageAWrapper

- (id)init
{
    self = [super init];
    if (self) {
        self.message = new MessageA();
    }
    return self;
}

- (void)dealloc {
    delete self.message;
    self.message = NULL;
}

- (NSString *)value {
    return [NSString stringWithUTF8String:self.message->value().c_str()];
}

- (void)setValue:(NSString *)value {
   self.message->set_value([value UTF8String]);
}

- (NSString *)serialize {
    std::string output;
    self.message->SerializeToString(&output);
    return [NSString stringWithUTF8String:output.c_str()];
}

+ (id)fromString:(NSString *)string {
    MessageA *message = new MessageA();
    message->ParseFromString([string UTF8String]);

    MessageAWrapper *wrapper = [[MessageAWrapper alloc] init];
    wrapper.message = message;
    return wrapper;
}

@end

目标

这里有很多代码会重复几十次,其中唯一的变化是包装类类型(init,dealloc,serialize,fromString),所以理想情况下我想将它放在父ProtobufMesssage类上.不幸的是,我没有成功完成这项工作,因为我无法找到父类知道其子节点所使用的类的方法,例如在init和fromString中.

我试过的事情

>结构

>模板类

>无效*

我遇到过的障碍

>找不到存储类/类型引用的方法

> .h文件中不能有任何C头文件或代码(因为这需要整个项目为Objective-C)

>难以保留对protobuf消息父(Message或MessageLite)的引用,因为它们是抽象的

正如我所说,我对C或Objective-C的理解很少;我的大部分经验都是使用更高级的语言,如Python和Java(虽然我主要理解像指针这样的基本C语言).

这可能甚至不可能吗?我接近错误或遗漏了一些明显的东西吗?任何帮助将非常感激.谢谢.

我根本不太了解C,但是你不能将Objective-C属性声明为Message *吗?

您已经通过声明.mm文件中的属性将C代码与标头分开了,您将遇到的问题是编译器命名的实例方法(value()和set_value())并且只是有效的方法.子类.使用Reflection类可以帮助他们按名称获取和设置字段.以下是Google的message.h的摘录,显示了以下内容:

Message* foo = new Foo;
const Descriptor* descriptor = foo->GetDescriptor();

const FieldDescriptor* text_field = descriptor->FindFieldByName("text");
assert(text_field != NULL);
assert(text_field->type() == FieldDescriptor::TYPE_STRING);
assert(text_field->label() == FieldDescriptor::LABEL_OPTIONAL);

const Reflection* reflection = foo->GetReflection();
assert(reflection->GetString(foo, text_field) == "Hello World!");

您可以创建Objective-C -objectForKey:和-setObject:forKey:类型检查并获取或设置值的实例方法(令人困惑的是,MessageAWrapper中的键将是@“value”).您的子类甚至不需要知道C代码.

您还可以将-init和fromString:方法中的creator函数分隔为_createNewInstance;

+(Message*)_createNewInstance{ return new MessageA(); }

允许MessageWrapper的子类重用除创建C对象之外的所有代码.

扫码领视频副本.gif

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号