19

是 iOS 的元语法静态库。. .

http://code.google.com/p/metasyntactic/wiki/ProtocolBuffers

. . . 与常规的旧 C++ 编译的原型文件兼容吗?我不想使用生成 Obj-C 的捆绑编译器。

有没有办法编译谷歌为 iOS 提供的库?

4

4 回答 4

19

好的。在这种情况下,元句法库(或任何其他第 3 方库)似乎是不必要的。您可以直接将 Google 源代码添加到您的项目中。我在 google 讨论组中找到了 Nicola Ferruzzi 的以下答案。. .

原来的答案在这里。. .

http://groups.google.com/group/protobuf/browse_thread/thread/ca4218d7db144252

该答案的内容包含在下面的图像中,以永久记录...


编辑

由于今晚第一次尝试这个,除了下面列出的步骤之外,我还需要几个步骤(这适用于 protobuf 2.5.0)。

  • 您需要链接到 libz.dylib。您可以在 Build Phases > Link Binary With Libraries 中进行设置。
  • 要轻松删除所有与单元测试相关的内容,请在 google 目录中的 shell 中使用以下命令find . -name "*unittest*" -exec rm -rf {} \;
  • 同时删除名为testing
  • 注释掉#include <google/protobuf/testing/googletest.h>_stringprintf.cc
  • 现在仔细按照以下说明进行操作,一切正常。

我在我的应用程序中使用最新版本.. 如果您熟悉 C++,您实际上并不需要 objc 直接支持,只有一点您必须从 std::string 传递到 NSData,反之亦然。它非常简单。

编译和测试我发现的最简单的方法是在我自己的项目中导入整个 google 目录:) (第二次你可以制作自己的框架,但为了测试这个过程就可以了)

  • 下载最新版本
  • autogen 配置和制作就像您刚刚为 macosx 构建一样(您需要命令行工具)。这样你最终得到了 protoc
    二进制文件和 macosx 库(你不需要)
  • 打开你的 Xcode iOS 项目
  • 将“新文件”添加到您的项目并选择 google 目录
  • 将 google headers 的目录添加到您的其他包含目录中
  • 将 protobuffer src 目录中的 config.h 添加到您的应用程序
  • 从 google 组中删除包含 unitest 的所有内容 :)
  • 从 google 组中删除编译器和 java 的东西;

您应该能够在没有任何链接错误的情况下进行编译。为了给你一个想法,这是我直接编译的

在此处输入图像描述

然后您可以使用 protoc 为您的协议生成 c++ 源文件。要将它们与 objc 一起使用,您必须将源重命名为文件“mm”,然后您可以执行类似的操作

序列化到 NSDATA

假设您的消息称为 Packet

- (NSData *)getDataForPacket:(Packet *)packet { 
    std::string ps = packet->SerializeAsString(); 
    return [NSData dataWithBytes:ps.c_str() length:ps.size()]; 

从 NSDATA 读取

- (Packet *)getPacketFromNSData:(NSData *)data { 
  char raw[[data length]]; 
  Packet *p = new Packet; 
  [data getBytes:raw length:[data length]]; 
  p->ParseFromArray(raw, [data length]); 
  return p; 

}
于 2012-04-23T11:29:15.300 回答
14

您可以通过将以下行添加到您的 Podfile 中,为使用 Cocoapods 的 Xcode 5 项目添加对 Google Protocol Buffers 的支持。

pod 'GoogleProtobuf', '~> 2.5.0'

这会将 C++ 版本的 protobuf 代码放入项目的 Pod 中。它还将在项目protoc的文件夹中添加编译器Pods/GoogleProtobuf/bin/protoc

您可以在项目中创建自定义构建规则,自动将.proto文件转换为.ph.{h,cc}文件。我是这样做的:

将构建规则设置为“处理名称匹配的源文件:*.proto 使用自定义脚本”。该脚本应包括以下内容:

cd ${INPUT_FILE_DIR}
${SRCROOT}/Pods/GoogleProtobuf/bin/protoc --proto_path=${INPUT_FILE_DIR} ${INPUT_FILE_PATH} --cpp_out=${INPUT_FILE_DIR}/cpp

设置输出文件以包括以下内容:

$(INPUT_FILE_DIR)/cpp/$(INPUT_FILE_BASE).pb.h
$(INPUT_FILE_DIR)/cpp/$(INPUT_FILE_BASE).pb.cc

您在项目中包含的任何.proto文件现在都将自动转换为 C++,然后作为构建的一部分进行编译。

于 2013-10-19T19:19:18.123 回答
12

编辑:我之前回答过这个问题,但被版主删除了。所以我已经包含了教程中的一些代码。

与上面发布的答案几乎相同的教程 -在 iOS 和 Mac 上的 Objective-C 中使用 Google 协议缓冲区

按照 learnvst 的答案中给出的步骤,并参考评论中的陷阱。我遵循完全相同的步骤,除了

将 google 标头目录添加到您的附加包含目录 我在标头搜索路径中添加了src/目录,而不是 google 目录。

另外,当我这样做#import xyz.pb.h的时候,项目还没有建立。当我将.m文件重命名为.mm时,我能够构建。教程中非常巧妙地提到了这一点:P。

基本上,导入任何.pb.h文件的任何.m文件都应使用扩展名.mm重命名

这是教程中的一些内容 -

原文件

package kotancode;

enum ZombieType {
    SLOW = 0;
    FAST = 1;
}

message ZombieSighting {
    required string name = 1;
    required double longitude = 2;
    required double latitude = 3;
    optional string description = 4;
    required ZombieType zombieType = 5 [default = SLOW];
}

ZombieSightingMessage.h

// -- ZombieSightingMessage.h - note my C++ object is not in the public interface.
#import <Foundation/Foundation.h>

@interface ZombieSightingMessage : NSObject
- (void)doSomething;
@end

ZombieSightingMessage.mm

// -- ZombieSightingMessage.mm
#import <UIKit/UIKit.h>
#import "ZombieSightingMessage.h"
#import "zombie.pb.h"

@implementation ZombieSightingMessage

- (void)doSomething {
    // Doing random stuff with a UIView here to show the mixing
    // of C++ and Objective-C/Cocoa syntax in the same file...
    UIView *uiView = [[UIView alloc] init];
    [uiView setCenter:CGPointMake(20, 10)];

    // instantiate my protobuf-generated C++ class.
    kotancode::ZombieSighting *zombieSighting = new kotancode::ZombieSighting();
    zombieSighting->set_name("Kevin");
    zombieSighting->set_description("This is a zombie");
    zombieSighting->set_latitude(41.007);
    zombieSighting->set_longitude(21.007);
    zombieSighting->set_zombietype(kotancode::ZombieType::FAST);

    // Some small tomfoolery required to go from C++ std::string to NSString.
    std::string x = zombieSighting->DebugString();
    NSString *output = [NSString stringWithCString:x.c_str() encoding:[NSString defaultCStringEncoding]];
    NSLog(@"zombie: %@", output);

    // Instantiate another zombie from the previous zombie's raw bytes.
    NSData *rawZombie = [self getDataForZombie:zombieSighting];
    kotancode::ZombieSighting *otherZombie = [self getZombieFromData:rawZombie];

    // Dump the second zombie so we can see they match identically...
    NSString *newOutput = [NSString stringWithCString:otherZombie->DebugString().c_str() encoding:[NSString defaultCStringEncoding]];
    NSLog(@"other zombie: %@", newOutput);

    // Grimace all you want, but this is C++ and we need to clean up after ourselves.
    free(zombieSighting);
    free(otherZombie);

}

// Serialize to NSData. Note this is convenient because
// we can write NSData to things like sockets...
- (NSData *)getDataForZombie:(kotancode::ZombieSighting *)zombie {
    std::string ps = zombie->SerializeAsString();
    return [NSData dataWithBytes:ps.c_str() length:ps.size()];
}

// De-serialize a zombie from an NSData object.
- (kotancode::ZombieSighting *)getZombieFromData:(NSData *)data {
    int len = [data length];
    char raw[len];
    kotancode::ZombieSighting *zombie = new kotancode::ZombieSighting;
    [data getBytes:raw length:len];
    zombie->ParseFromArray(raw, len);
    return zombie;
}

@end

编辑:我正在使用 Xcode 4.5。即使在我按照所有步骤操作之后,我也遇到了链接器错误。

未找到体系结构 i386 的符号

因此,我无法在模拟器上运行代码。但它适用于实际设备

于 2013-03-06T11:41:57.980 回答
2

我想根据实际问题,我的评论值得作为答案发布:

我正在使用Booyah提供的本机 Obj 代码生成的略微修改版本

它支持开箱即用的重复字段,但为了使用 ObjC 快速枚举,您需要将 PBArray 类型(基本上是类型化的 c 缓冲区)转换为它所代表的 NSObject 数组——对象的 NSNumber 或 protobuf 消息。您可以在此更改中看到更新的快速枚举代码示例:。您还可以在 PBArray 上添加一个名为 toObjects 的类别。

我只是用 标记生成的代码,但您可以从booyah 拉取请求-fno-objc-arc中获得 arc 和 2.5 支持。

这些说明非常适合设置,但如果人们想要更明确地说明我使用的类别、我如何构建 protobuf-objc 插件、如何获得对类前缀的支持(例如 IXMyProtoMessage 而不是 MyProtoMessage)或我如何生成代码让我知道,我会尽量腾出时间写一篇文章。我将它与> 50个具有很多跨项目依赖关系的原型文件一起使用。

该库的一个弱点是它在生成的代码中不包含典型的 Protobuf 反射 api,因此执行诸如将消息转换为 NSDictionary 之类的操作将不得不对 objC 运行时做一些骇人听闻的事情(代码不遵循典型的KV 合规性)或从具有反射 api 的 protos 编写自定义代码生成器(我使用 python + jinja2 完成了此操作)。或者 - 更好和类似的困难,将反射 API 添加到代码生成器;)。

于 2013-08-07T18:45:45.180 回答