My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
ProtocolBuffers  
Objective-C Protocol Buffers for OSX and the iPhone
Updated Feb 4, 2010 by cyrus.na...@gmail.com

Introduction

Protocol Buffers are a way of encoding structured data in an efficient yet extensible format. For more information see the main page here.

This project contains a port of Protocol Buffers that can be used in OSX 10.5 and later and on the iPhone OS 2.0 and later.

The port includes a Protocol Buffer compiler (protoc) and a Protocol Buffer static library that you link into any project that you want protobuf support for. The protoc compiler supports almost all the features of the protobuf 2 language and when given .proto files as input will generate the specialized Objective-C classes necessary to both read and write instances of the messages contained therein. These classes, along with the supplied static library, will then allow your code to read and write protobuf instances simply and in a typesafe manner.

Quick Example

You write a .proto file like this:

message Person {
  required int32 id = 1;
  required string name = 2;
  optional string email = 3;
}

Then you compile it with protoc, the protocol buffer compiler, to produce code in Objective-C.

You use that code like this to produce raw protobuf data from a message:

Person* person = [[[[[Person builder] setId:123]
                                    setName:@"Bob"]
                                   setEmail:@"bob@example.com"] build];
NSData* data = [person data];

Or like this to read a message back from raw protobuf data:

NSData* raw_data = ...;
Person* person = [Person parseFromData:raw_data];

Gory Details

Creating the Protocol Buffer Compiler (protoc)

In order to compiler and use protoc you must first have installed XCode and the rest of Apple's developer tools.

  1. Download and unzip the latest ProtocolBuffers-*.*-Source.tar.gz file in the download section to <install_directory> on your computer.
  2. Navigate to <install_directory> and type the following commands
  3. ./autogen.sh
  4. ./configure
  5. make

protoc will then be built into the <install_directory>/src directory.

Compiler Invocation

For full details on the protobuf compiler, please see the official details here

The protocol buffer compiler (protoc) produces Objective-C output when invoked with the --objc_out= command-line flag. The parameter to the --objc_out= option is the directory where you want the compiler to write your Objective-C output. The compiler creates a header file and an implementation file for each .proto file input. The names of the output files are computed by taking the name of the .proto file and making two changes:

  • The extension (.proto) is replaced with either .pb.h or .pb.m for the header or implementation file, respectively.
  • The proto path (specified with the --proto_path= or -I command-line flag) is replaced with the output path (specified with the --objc_out= flag).
So, for example, let's say you invoke the compiler as follows:

protoc --proto_path=src --objc_out=build/gen src/foo.proto src/bar/baz.proto

The compiler will read the files src/foo.proto and src/bar/baz.proto and produce four output files: build/gen/foo.pb.h, build/gen/foo.pb.m, build/gen/bar/baz.pb.h, build/gen/bar/baz.pb.m. The compiler will automatically create the directory build/gen/bar if necessary, but it will not create build or build/gen; they must already exist.

Project Integration

Once you have generated the .pb.h and .pb.m files for the .proto file you care about, you can then add them to your project. However, in order to build properly several changes must be made to your project.

  1. Download and unzip the latest ProtocolBuffers-*.*-Source.tar.gz file in the download section to <install_directory> on your computer. (This should have been done in the 'Creating the Protocol Buffer Compiler' step above).
  2. Open your existing project and a reference to the ProtocolBuffers project found in <install_directory>.
  3. Add a reference to <install_directory>/Classes/ProtocolBuffers.h in your project and add the following line to your pch file: #import "ProtocolBuffers.h"
  4. Get Info on your build target
  5. Add ProtocolBuffers as a Direct Dependency of your build target.
  6. Add libProtocolBuffers.a as a Linked Library of your build target. You may have to do this by dragging and dropping the library from the referenced ProtocolBuffers project to your target's Link Binary With Libraries section.
  7. Compile and enjoy!

Extensions

In order to more seamlessly integrate with Objective-C code, this library also extends the standard google.protobuf.FileOptions message with the following options:

  // Sets the ObjectiveC package where classes generated from this .proto
  // will be placed.  This is typically used since Objective C libraries output
  // all their headers into a single directory.  i.e.  Foundation\*
  // AddressBook\*   UIKit\*   etc. etc.
  optional string package = 1;
  
  // The string to be prefixed in front of all classes in order to make them
  // 'cocoa-y'.  i.e. 'NS/AB/CF/PB' for the
  // NextStep/AddressBook/CoreFoundation/ProtocolBuffer libraries respectively.
  // This will commonly be the capitalized letters from the above defined
  // 'objectivec_directory'
  optional string class_prefix = 2;

To use these extensions you will need to add the following to your proto file:

import "google/protobuf/objectivec-descriptor.proto";

option (google.protobuf.objectivec_file_options).package = "<your package>"
option (google.protobuf.objectivec_file_options).class_prefix = "<your class prefix>";

(note that the parent folder to 'google/protobuf/objectivec-descriptor.proto' must be in your include path when compiling your protocol buffer).

By using these options, you can integrate existing protobuf definitions, while still producing Objective-C code that meets expected styling standards. For example, this library uses those options above to emit the core protobuf Descriptor types into a "ProtocolBuffers" directory with a common "PB" prefix on all classes. Thus, while you would say the following in java:

import google.protobuf.Descriptor;

in Objective-C you would say:

import "ProtocolBuffers\PBDescriptor.h"

Example

Here's an example of how I integrate the library into my own 'Now Playing' application. Note the reference to the project, the direct dependency in the target, and the shared lib in the link section.

Help/Support

If you need any help/support with this feel free to email me at cyrus.najmabadi@gmail.com.

Cheers!

Comment by geeo...@gmail.com, Feb 5, 2010

A big big thanks to Cyrus. He's very helpful with "lost" users :)

Comment by ofri@google.com, Aug 15, 2010

Rename the directory of the source to something without space and special characters, like "ProtoBuff?".

Comment by project member cyrus.na...@gmail.com, Aug 20, 2010

Why?

Comment by GaryRudo...@gmail.com, Aug 26, 2010

Any chance to update to proto 2.3.0?

Comment by MasoodMo...@gmail.com, Oct 19, 2010

Does this port to FreeBSD?

Comment by project member cyrus.na...@gmail.com, Oct 19, 2010

I don't understand your question Masood.

Comment by thomas.w...@gmx.de, Oct 27, 2010

Can you clarify on the code license of protobuf-objc?

Currently the code is covered by "GNU General Public License v2" which you have choosen for your metasyntactic project. This would prohibit using your library for commercial software. Is this intentional? Are you planning to offer a commercial license in addition?

Comment by project member cyrus.na...@gmail.com, Oct 27, 2010

As you can see from teh individual source files in the protobuf distro, it is apache licensed. Cheers!

Comment by jap...@gmail.com, Oct 30, 2010

I'm playing around with protcol buffers using gnustep on linux. protoc builds fine, but I'm getting import errors when I try to compile the generated files.

user@host:~/src/test$ gcc Test.pb.m -I/usr/include/GNUstep -lobjc -lgnustep-bas
e -fconstant-string-class=NSConstantString -I/home/jape/ProtocolBuffers-2.2.0-S
ource/objectivec/Classes

In file included from /home/jape/ProtocolBuffers-2.2.0-Source/objectivec/Classes
/Bootstrap.h:17,
                 from /home/jape/ProtocolBuffers-2.2.0-Source/objectivec/Classes
/ProtocolBuffers.h:15,
                 from Test.pb.h:3,
                 from Test.pb.m:3:
/home/jape/ProtocolBuffers-2.2.0-Source/objectivec/Classes/CodedInputStream.h:27
: error: cannot find interface declaration for NSObject, superclass of 
PBCodedInputStream

Any ideas?

jp

Comment by project member cyrus.na...@gmail.com, Nov 2, 2010

Sounds like a question to ask the gnustep people about. That's not a configuration i support.

Comment by jap...@gmail.com, Nov 8, 2010

Ah. I see what's happening now. Xcode automatically includes <Framework/Framework.h> on every file for you. I was able to fix my problem by adding this to the .h files. This seemed to result in an include loop so I added

#ifndef _THE_INCLUDE_FILE
#define _THE_INCLUDE_FILE
...
#endif

around the whole include.

It seems that this implementation only supports the serialization of data structs and doesn't support the rpc service stub generation. Is that correct?

regards

jp

Comment by project member cyrus.na...@gmail.com, Nov 9, 2010

Correct, only serialization of data structs.

Comment by joesha...@gotspam.com, Jan 13, 2011

I followed the instructions above, however, when I try to build the protocol files (.m and .h) in a test Xcode project, I get the following errors. When I look at the library(ar -t), there aren't any "PB" prefixes on any of the objects. Has anyone else had any luck with this?

errors(There are 11, I'm only attaching a couple):

"OBJC_CLASS$PBGeneratedMessage", referenced from: OBJC_CLASS$Person in Person.pb.o "OBJC_IVAR$PBGeneratedMessage.memoizedSerializedSize", referenced from: OBJC_IVAR$PBGeneratedMessage.memoizedSerializedSize$non_lazy_ptr in Person.pb.o (maybe you meant: OBJC_IVAR$PBGeneratedMessage.memoizedSerializedSize$non_lazy_ptr) "OBJC_CLASS$PBUnknownFieldSet", referenced from:

Comment by Bengt.Br...@gmail.com, Jan 26, 2011

there is a bug in class codetInputStream. look at @fix tag

- (BOOL) refillBuffer:(BOOL) mustSucceed {

...

// @fix(bbrodersen) here it is important to check if {@code input} has available bytes, otherwise the program will if you call {input read ...] stuck in a loop (dont know what loop) if (input != nil && hasBytesAvailable?) {
bufferSize = read:buffer.mutableBytes maxLength:buffer.length?;
}

...

}

Comment by rich.burdon, Feb 9, 2011

I'm getting a bunch of errors like the ones below when trying to compile the generated .m file.

I've copied the libProtocolBuffers.a file from ROOT/objectivec/build/Debug-iphoneos

Undefined symbols:

".objc_class_name_NSException", referenced from:
literal-pointer@OBJC@cls_refs@NSException in libProtocolBuffers.a(AbstractMessage?.o) literal-pointer@OBJC@cls_refs@NSException in libProtocolBuffers.a(AbstractMessage_Builder?.o) literal-pointer@OBJC@cls_refs@NSException in libProtocolBuffers.a(CodedInputStream?.o) literal-pointer@OBJC@cls_refs@NSException in libProtocolBuffers.a(CodedOutputStream?.o) literal-pointer@OBJC@cls_refs@NSException in libProtocolBuffers.a(ExtendableMessage?.o) literal-pointer@OBJC@cls_refs@NSException in libProtocolBuffers.a(GeneratedMessage_Builder?.o) literal-pointer@OBJC@cls_refs@NSException in libProtocolBuffers.a(TextFormat?.o) literal-pointer@OBJC@cls_refs@NSException in libProtocolBuffers.a(UnknownFieldSet_Builder?.o) literal-pointer@OBJC@cls_refs@NSException in libProtocolBuffers.a(ExtendableMessage_Builder?.o) literal-pointer@OBJC@cls_refs@NSException in libProtocolBuffers.a(ConcreteExtensionField?.o)

Comment by cloud9te...@gmail.com, Mar 19, 2011

@ joesha...@gotspam.com

Did you resolve this? Is libProtocolBuffers.a in your linked libraries?

Comment by klaas...@gmail.com, May 13, 2011

Are there any plans to maintain the Objective-C support of protocol buffers in the future? I just configured your solution using XCode 4 and really like it, but I'm not sure, if I can use it in an production environment, if the development has stopped.

So, any thoughts on this? ;)

Powered by Google Project Hosting