Protocol Buffers:Objective-C Reference

Objective-C Generated Code

  • [Compiler invocation - 编译器调用]
  • [Packages - 包]
  • [Class prefix - 类前缀]
  • [Camel case conversion - 驼峰式转换]
  • [Messages - 消息]
  • [Fields - 字段]
  • [Enumerations]
  • [Well-known types (proto3 only) - 未知字段(仅proto3)]
  • [Extensions (proto2 only) - 扩展(仅proto2)]

This page describes exactly what Objective-C code the protocol buffer compiler generates for any given protocol definition. Any differences between proto2 and proto3 generated code are highlighted. You should read the proto2 language guide and/or proto3 language guide before reading this document.
该篇精确地描述了protocol buffer编译器根据任何给定的protocol 定义生成的Objective-C代码。突出显示了proto2和proto3生成的代码之间的任何差异。在阅读该文档前你应该先阅读proto2语言指南和/或proto3语言指南。

Compiler invocation - 编译器调用

The protocol buffer compiler 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 the following changes:
当使用 "-objc_out=" 命令行标识调用时,protocol buffer 编译器会生成Objective-C输出。--objc_out=选项的参数值就是你想要编译器写入Objective-C输出的目录。编译器为每一个.proto文件输入都生成一个头文件和一个实现文件。输出文件的名称是通过获取.proto文件名称并进行以下更改来计算的:

The file name is determined by converting the .proto file base name to camel case. For example, foo_bar.proto will become FooBar.
The extension (.proto) is replaced with either pbobjc.h or pbobjc.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, if you invoke the compiler as follows:
文件名由转换.proto文件基础名为驼峰式决定的。举个例子,foot_bar.prot会变为FooBar。扩展名(.proto)依次由头文件pbobjc.h或实现文件pbobjc.m所替换。proto路径(由--proto_path=或-I命令行标志所指定)被输出路径(由--objc_out=标志)所替换。所以,举个例子,如果你如下调用编译器:

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.pbobjc.h, build/gen/Foo.pbobjc.m, build/gen/bar/Baz.pbobjc.h, and build/gen/bar/Baz.pbobjc.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.
编译器会读取src/foo.proto 和 src/bar/baz.proto文件,然后生成四个输出文件:build/gen/Foo.pbobjc.h, build/gen/Foo.pbobjc.m, build/gen/bar/Baz.pbobjc.h, 和 build/gen/bar/Baz.pbobjc.m。如果需要编译器会自动创建build/gen/bar目录,但是它不会创建build或build/gen;它们必须已经存在。

Packages - 包

The Objective-C code generated by the protocol buffer compiler is completely unaffected by the package name defined in the .proto file, as Objective-C has no language-enforced namespacing. Instead, Objective-C class names are distinguished using prefixes, which you can find out about in the next section.
protocol buffer 编译器生成的Objective-C代码是完全不受定义在.proto文件中的包名影响,因为Objective-C没有语言强制命名空间。相反,Objective-C类名使用前缀区分,你可以在下一节中找到相关信息。

Class prefix - 类前缀

Given the following file option:
给定以下文件选项:

option objc_class_prefix = "CGOOP";

The specified string - in this case, CGOOP - is prefixed in front of all Objective-C classes generated for this .proto file. Please use prefixes that are 3 or more characters as recommended by Apple. Note that all 2 letter prefixes are reserved by Apple.
本例中指定的字符串为CGOOP - 位于所有为此.proto文件生成的Objective-C类的前面。使用Apple推荐的三个或更多字符。注意所有2个字符的前缀由苹果保留。

Camel case conversion - 驼峰式转换

Idiomatic Objective-C uses camel case for all identifiers.
Objective-C 对所有标识符使用驼峰式大小写。

Messages will not have their names converted because the standard for proto files is to name messages in camel case already. It is assumed that the user has bypassed the convention for good reason, and the implementation will conform with their intentions.
消息的名称不会被转换,因为proto文件的标准是已经以驼峰式命名消息。假设用有充分的理由绕开了规则,并且实现会符合他们的意图。

Methods generated from field names and oneofs, enum declarations, and extension accessors will have their names camel cased. In general to convert from a proto name to a camel cased Objective-C name:
由字段名称和oneof,枚举定义,和扩展访问器生成的方法会以驼峰式命名。通常从proto名称转换为驼峰式Objective-C名称:

  • The first letter converted to uppercase (except for fields, which always start with a lowercase letter).
    首字母转换为大写(除了字段,其总是以小写字母开头)。

  • For each underscore in the name, the underscore is removed, and the following letter is capitalized.
    名称中的下划线会被删除,其下一个字母会被大写。

So, for example, the field foo_bar_baz becomes fooBarBaz. The field FOO_bar becomes fooBar.
举个例子,foo_bar_baz字段会变为fooBarBaz。FOO_bar会变为fooBar。

Messages - 消息

Given a simple message declaration:
给定一个消息定义示例:

message Foo {}

The protocol buffer compiler generates a class called Foo. If you specify an objc_class_prefix file option, the value of this option is prepended to the generated class name.
protocol buffer 编译器生成一个Foo类,如果你指定一个objc_class_prefix 文件选项,该选项的值会追加在生成类名的头部。

In the case of outer messages that have names matching any C/C++ or Objective-C keywords:
对于名称与C/C++或者Objective-C任何键字匹配的外部消息:

message static {}

the generated interfaces are suffixed by _Class, as follows:
生成的接口会以_Class为后缀,如下:

@interface static_Class {}

Note that as per the camel case conversion rules the name static is not converted. In the case of an inner message that has a camel cased name that is FieldNumber or OneOfCase, the generated interface will be the camel cased name suffixed by _Class to make sure that the generated names do not conflict with the FieldNumber enumerations or OneOfCase enumerations.
注意根据驼峰式转换规则,名称static不会转换。对于消息内部有驼峰式命名如FieldNumberOneOfCase的情况,生成的接口将是后缀为 _Class 的驼峰命名,来保证生成的名称不和FieldNumber枚举或OneOfCase枚举冲突。

A message can also be declared inside another message.
一个消息也可以定义在另一个消息内部:

message Foo {
  message Bar {}
}

This generates:
这生成:

@interface Foo_Bar : GPBMessage
@end

As you can see, the generated nested message name is the name of the generated containing message name (Foo) appended with underscore () and the nested message name (Bar).
正如你看到的,生成的嵌套消息名称是生成的外层消息名称(Foo)后加下划线(
)和嵌套消息名称(Bar)的名称。

While we have tried to ensure that conflicts are kept to a minimum, there are still potential cases where message names may conflict due to the conversion between underscores and camel case. As an example:
虽然我们已尽力确保将冲突保持在最低限度,仍然有潜在可能,消息名在下划线和驼峰式之间转换时冲突。举个例子:

message foo_bar {} 
message foo { message bar {} } 

will both generate @interface foo_bar and will conflict. The most pragmatic solution may be to rename the conflicting messages.
都会生成@interface foo_bar导致冲突。最实际的解决办法是重命名冲突的消息。

GPBMessage interface - GPBMessage接口

GPBMessage is the superclass of all generated message classes. It is required to support a superset of the following interface:
GPBMessage是所有生成的消息类的父类。这个需要支持以下接口的超集:

@interface GPBMessage : NSObject 
@end

The behaviors for this interface are as follows:
该接口行为如下:

// Will do a deep copy.
- (id)copy;
// Will perform a deep equality comparison.
- (BOOL)isEqual:(id)value;
Unknown fields (proto2 only) - 未知字段(仅proto2)

If a message created with an older version of your .proto definition is parsed with code generated from a newer version (or vice versa), the message may contain optional or repeated fields that the "new" code does not recognize. In proto2 generated code, these fields are not discarded and are stored in the message's unknownFields property.
如果新版本生成的代码解析旧版本.proto 定义创建的消息,消息中可能包含可选或重复字段,而“新”代码无法识别。在proto2生成的代码中,这些字段不会被忽略,而是存储在消息的unknownFields属性中。

@property(nonatomic, copy, nullable) GPBUnknownFieldSet *unknownFields;

You can use the GPBUnknownFieldSet interface to fetch these fields by number or loop over them as an array.
In proto3, unknown fields are simply discarded when a message is parsed.
你可以使用GPBUnknownFieldSet接口像数组那样通过数字或循环获取这些字段。

Fields - 字段

The following sections describe the code generated by the protocol buffer compiler for message fields.
接下来的章节描述了protocol buffer编译器生成的消息字段代码。

Singular fields (proto3) - 单一字段(proto3)

For every singular field the compiler generates a property to store data and an integer constant containing the field number. Message type fields also get a has.. property that lets you check if the field is set in the encoded message. So, for example, given the following message:
对于每个单一字段编辑器会生成一个属性来存储数据和一个整型常量来包含字段数字。消息类型字段会获得一个has..属性,来让你在编码消息中检测字段是否被设置。举个例子,给定如下消息:

message Foo {
  message Bar {
    int32 int32_value = 1;
  }
  enum Qux {...}
  int32 int32_value = 1;
  string string_value = 2;
  Bar message_value = 3;
  Qux enum_value = 4;
  bytes bytes_value = 5;
}

The compiler will generate the following:
编译器生成的代码如下:

typedef GPB_ENUM(Foo_Bar_FieldNumber) {
  // The generated field number name is the enclosing message names delimited by
  // underscores followed by "FieldNumber", followed by the field name
  // camel cased.
  Foo_Bar_FieldNumber_Int32Value = 1,
};

@interface Foo_Bar : GPBMessage
@property(nonatomic, readwrite) int32_t int32Value;
@end

typedef GPB_ENUM(Foo_FieldNumber) {
  Foo_FieldNumber_Int32Value = 1,
  Foo_FieldNumber_StringValue = 2,
  Foo_FieldNumber_MessageValue = 3,
  Foo_FieldNumber_EnumValue = 4,
  Foo_FieldNumber_BytesValue = 5,
};

typedef GPB_ENUM(Foo_Qux) {
  Foo_Qux_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
  ...
};

@interface Foo : GPBMessage
// Field names are camel cased.
@property(nonatomic, readwrite) int32_t int32Value;
@property(nonatomic, readwrite, copy, null_resettable) NSString *stringValue;
@property(nonatomic, readwrite) BOOL hasMessageValue;
@property(nonatomic, readwrite, strong, null_resettable) Foo_Bar *messageValue;
@property(nonatomic, readwrite) Foo_Qux enumValue;
@property(nonatomic, readwrite, copy, null_resettable) NSData *bytesValue;
@end

Special naming cases
特殊命名情况

There are cases where the field name generation rules may result in name conflicts and names will need to be "uniqued". Such conflicts are resolved by appending _p to the end of the field (_p was selected because it's pretty unique, and stands for "property").
有些情况字段名称生成规则可能会导致命名冲突,命名需要是“唯一的”。有些冲突是通过在字段末尾拼接_p解决(选择_p是因为它非常独特,且代表了“protperty”(属性))。

message Foo {
  int32 foo_array = 1;      // Ends with Array
  int32 bar_OneOfCase = 2;  // Ends with oneofcase
  int32 id = 3;             // Is a C/C++/Objective-C keyword
}

generates:
生成:

typedef GPB_ENUM(Foo_FieldNumber) {
  // If a non-repeatable field name ends with "Array" it will be suffixed
  // with "_p" to keep the name distinct from repeated types.
  Foo_FieldNumber_FooArray_p = 1,
  // If a field name ends with "OneOfCase" it will be suffixed with "_p" to
  // keep the name distinct from OneOfCase properties.
  Foo_FieldNumber_BarOneOfCase_p = 2,
  // If a field name is a C/C++/ObjectiveC keyword it will be suffixed with
  // "_p" to allow it to compile.
  Foo_FieldNumber_Id_p = 3,
};

@interface Foo : GPBMessage
@property(nonatomic, readwrite) int32_t fooArray_p;
@property(nonatomic, readwrite) int32_t barOneOfCase_p;
@property(nonatomic, readwrite) int32_t id_p;
@end

Default values - 默认值

The default value for numeric types is 0.
数字类型的默认值是0

The default value for strings is @"", and the default value for bytes is [NSData data].
string的默认值是@"",byte的默认值是[NSData data]

Assigning nil to a string field will assert in debug, and set the field to @"" in release. Assigning nil to a bytes field will assert in debug and set the field to [NSData data] in release. To test whether a bytes or string field is set requires testing its length property and comparing it to 0.
在debug模式下给string字段赋值nil会触发assert,release模式下会设置字段值为@""。在debug模式下给byte字段赋值nil会触发assert,release模式下会设置字段值为[NSData data]。为了验证byte或string是否被赋值,需要将其长度和0进行比较。

The default "empty" value for a message is an instance of the default message. To clear a message value it should be set to nil. Accessing a cleared message will return an instance of the default message and the hasFoo method will return false.
message默认“空值”是一个默认的message实例。清理一个message应该将其赋值为nil。访问一个已经被清理掉的message会返回一个默认message的实例,并且hasFoo方法会返回false。

The default message returned for a field is a local instance. The reason behind returning a default message instead of nil is that in the case of:
字段的默认message是一个本地实例。返回默认默认message而不是nil的原因,是在这种情况下:

message Foo {
  message Bar {
     int32 b;
  }
  Bar a;
}

The implementation will support:
实现会支持:

Foo *foo = [[Foo alloc] init];
foo.a.b = 2;

where a will be automatically created via the accessors if necessary. If foo.a returned nil, the foo.a.b setter pattern would not work.
如果有必要,a将通过访问器自动创建,如果foo.a返回nil,foo.a.b
设值函数表达式将不起作用。

Singular fields (proto2) - 单一字段(proto2)

For every singular field the compiler generates a property to store data, an integer constant containing the field number, and a has.. property that lets you check if the field is set in the encoded message. So, for example, given the following message:
对于每一个单一字段,编译器会生成一个属性来存储数据,一个整型常量包含了字段数字,和一个has..属性用来让你检查该字段在编码后的message中是否被设值。举个例子,给定以下message:

message Foo {
  message Bar {
    int32 int32_value = 1;
  }
  enum Qux {...}
  optional int32 int32_value = 1;
  optional string string_value = 2;
  optional Bar message_value = 3;
  optional Qux enum_value = 4;
  optional bytes bytes_value = 5;
}

The compiler will generate the following:
编译器会生成如下代码:

# Enum Foo_Qux

typedef GPB_ENUM(Foo_Qux) {
  Foo_Qux_Flupple = 0,
};

GPBEnumDescriptor *Foo_Qux_EnumDescriptor(void);

BOOL Foo_Qux_IsValidValue(int32_t value);

# Message Foo

typedef GPB_ENUM(Foo_FieldNumber) {
  Foo_FieldNumber_Int32Value = 2,
  Foo_FieldNumber_MessageValue = 3,
  Foo_FieldNumber_EnumValue = 4,
  Foo_FieldNumber_BytesValue = 5,
  Foo_FieldNumber_StringValue = 6,
};

@interface Foo : GPBMessage

@property(nonatomic, readwrite) BOOL hasInt32Value;
@property(nonatomic, readwrite) int32_t int32Value;

@property(nonatomic, readwrite) BOOL hasStringValue;
@property(nonatomic, readwrite, copy, null_resettable) NSString *stringValue;

@property(nonatomic, readwrite) BOOL hasMessageValue;
@property(nonatomic, readwrite, strong, null_resettable) Foo_Bar *messageValue;

@property(nonatomic, readwrite) BOOL hasEnumValue;
@property(nonatomic, readwrite) Foo_Qux enumValue;

@property(nonatomic, readwrite) BOOL hasBytesValue;
@property(nonatomic, readwrite, copy, null_resettable) NSData *bytesValue;

@end

# Message Foo_Bar

typedef GPB_ENUM(Foo_Bar_FieldNumber) {
  Foo_Bar_FieldNumber_Int32Value = 1,
};

@interface Foo_Bar : GPBMessage

@property(nonatomic, readwrite) BOOL hasInt32Value;
@property(nonatomic, readwrite) int32_t int32Value;

@end
Special naming cases - 特殊命名情况

There are cases where the field name generation rules may result in name conflicts and names will need to be "uniqued". Such conflicts are resolved by appending _p to the end of the field (_p was selected because it's pretty unique, and stands for "property").
有些情况字段名称生成规则可能会导致命名冲突,命名需要是“唯一的”。有些冲突是通过在字段末尾拼接_p解决(选择_p是因为它非常独特,且代表了“protperty”(属性))。


message Foo {
  optional int32 foo_array = 1;      // Ends with Array
  optional int32 bar_OneOfCase = 2;  // Ends with oneofcase
  optional int32 id = 3;             // Is a C/C++/Objective-C keyword
}

generates:
生成:

typedef GPB_ENUM(Foo_FieldNumber) {
  // If a non-repeatable field name ends with "Array" it will be suffixed
  // with "_p" to keep the name distinct from repeated types.
  Foo_FieldNumber_FooArray_p = 1,
  // If a field name ends with "OneOfCase" it will be suffixed with "_p" to
  // keep the name distinct from OneOfCase properties.
  Foo_FieldNumber_BarOneOfCase_p = 2,
  // If a field name is a C/C++/ObjectiveC keyword it will be suffixed with
  // "_p" to allow it to compile.
  Foo_FieldNumber_Id_p = 3,
};

@interface Foo : GPBMessage
@property(nonatomic, readwrite) int32_t fooArray_p;
@property(nonatomic, readwrite) int32_t barOneOfCase_p;
@property(nonatomic, readwrite) int32_t id_p;
@end

Default values (optional fields only) - 默认值(仅可选字段)

The default value for numeric types, if no explicit default was specified by the user, is 0.
如果用户没有明确指定,数字类型默认值是0。

The default value for strings is @"", and the default value for bytes is [NSData data].
string的默认值是@"",byte默认值是[NSData data]

Assigning nil to a string field will assert in debug, and set the field to @"" in release. Assigning nil to a bytes field will assert in debug and set the field to [NSData data] in release. To test whether a bytes or string field is set requires testing its length property and comparing it to 0.
在debug模式下给一个string字段赋值为nil会触发断言,release下设置字段值为@""。在debug模式下给一个byte字段赋值为nil会触发断言,release下设置字段值为[NSData data]。判断byte或string类型字段是否被设值,需检测其length属性并和0比较。

The default "empty" value for a message is an instance of the default message. To clear a message value it should be set to nil. Accessing a cleared message will return an instance of the default message and the hasFoo method will return false.
message的默认“空值”是一个message实例。清理一个message值应该将其设置为nil。访问一个已经清理的message会返回一个默认message实例,hasFoo方法会返回false。

The default message returned for a field is a local instance. The reason behind returning a default message instead of nil is that in the case of:
一个字段的默认message是一个本地实例。返回一个默认message而不是nil,原因看下面这种情况:

message Foo {
  message Bar {
     int32 b;
  }
  Bar a;
}

The implementation will support:
实现会支持:

Foo *foo = [[Foo alloc] init];
foo.a.b = 2;

where a will be automatically created via the accessors if necessary. If foo.a returned nil, the foo.a.b setter pattern would not work.
如果需要,a会通过访问器自动创建。如果foo.a返回nil,foo.a.b构造函数格式将不起用。

Repeated fields - 重复字段

Like singular fields(proto2 proto3), the protocol buffer compiler generates one data property for each repeated field. This data property is a GPBArray depending on the field type where can be one of UInt32, Int32, UInt64, Int64, Bool, Float, Double, or Enum. NSMutableArray will be used for string, bytes and messagetypes. Field names for repeated types have Array appended to them. The reason for appending Array in the Objective-C interface is to make the code more readable. Repeated fields in proto files tend to have singular names which do not read well in standard Objective-C usage. Making the singular names plural would be more idiomatic Objective-C, however pluralization rules are too complex to support in the compiler.
和单一字段一样(proto2 proto3),protocol buffer编译器为每一个重复字段生成一个数据属性。这个数据属性是一个取决于字段类型的GPBArray类型,可以是UInt32, Int32, UInt64, Int64, Bool, Float, Double, 或Enum中的一种。重复类型的字段名称附加有Array。在Objective-C接口中拼接Array的原因是使代码更具可读性。proto文件中的重复字段往往有一个单数名称,这在在标准Objective-C用法中不太好读。将单数名称设为复数更符合Objective-C的语言习惯,然而在编译器中支持复数规则太复杂。

message Foo {
  message Bar {}
  enum Qux {}
  repeated int32 int32_value = 1;
  repeated string string_value = 2;
  repeated Bar message_value = 3;
  repeated Qux enum_value = 4;
}

generates:

typedef GPB_ENUM(Foo_FieldNumber) {
  Foo_FieldNumber_Int32ValueArray = 1,
  Foo_FieldNumber_StringValueArray = 2,
  Foo_FieldNumber_MessageValueArray = 3,
  Foo_FieldNumber_EnumValueArray = 4,
};

@interface Foo : GPBMessage
// Field names for repeated types are the camel case name with
// "Array" suffixed.
@property(nonatomic, readwrite, strong, null_resettable)
 GPBInt32Array *int32ValueArray;
@property(nonatomic, readonly) NSUInteger int32ValueArray_Count;

@property(nonatomic, readwrite, strong, null_resettable)
 NSMutableArray *stringValueArray;
@property(nonatomic, readonly) NSUInteger stringValueArray_Count;

@property(nonatomic, readwrite, strong, null_resettable)
 NSMutableArray *messageValueArray;
@property(nonatomic, readonly) NSUInteger messageValueArray_Count;

@property(nonatomic, readwrite, strong, null_resettable)
 GPBEnumArray *enumValueArray;
@property(nonatomic, readonly) NSUInteger enumValueArray_Count;
@end

For string, bytes and message fields, elements of the array are NSString, NSData and pointers to subclasses of GPBMessage respectively.
对于string,byte和messge字段,数组中的元素分别是NSString, NSData和GPBMessage子类指针。

Default values - 默认值

The default value for a repeated field is to be empty. In Objective-C generated code, this is an empty GPBArray. If you access an empty repeated field, you'll get back an empty array that you can update like any other repeated field array.
重复字段的默认值是空。在Objective-C生成的代码中,这是一个空GPBArray。如果你访问一个空的重复字段,你会得到一个空数组,并且你可以像其他重复字段数组一样更新它。

Foo *myFoo = [[Foo alloc] init];
[myFoo.stringValueArray addObject:@"A string"]

You can also use the provided Array_Count property to check if the array for a particular repeated field is empty without having to create the array:
你也可以使用所提供的Array_Count属性检测特定的重复字段是否为空,而无需创建该数组:

if (myFoo.messageValueArray_Count) {
  // There is something in the array...
}

GPBArray interface - GPBArray接口

GPBArrays (aside from GPBEnumArray, which we'll look at below) have the following interface:
GPBArrays(除了GPBEnumArray,下边我们会看到)有如下接口:

@interface GPBArray : NSObject 
@property (nonatomic, readonly) NSUInteger count;
+ (instancetype)array;
+ (instancetype)arrayWithValue:()value;
+ (instancetype)arrayWithValueArray:(GPBArray *)array;
+ (instancetype)arrayWithCapacity:(NSUInteger)count;

// Initializes the array, copying the values.
- (instancetype)initWithValueArray:(GPBArray *)array;
- (instancetype)initWithValues:(const  [])values
                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithCapacity:(NSUInteger)count;

- ()valueAtIndex:(NSUInteger)index;

- (void)enumerateValuesWithBlock:
     (void (^)( value, NSUInteger idx, BOOL *stop))block;
- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts 
    usingBlock:(void (^)( value, NSUInteger idx, BOOL *stop))block;

- (void)addValue:()value;
- (void)addValues:(const  [])values count:(NSUInteger)count;
- (void)addValuesFromArray:(GPBArray *)array;

- (void)removeValueAtIndex:(NSUInteger)count;
- (void)removeAll;

- (void)exchangeValueAtIndex:(NSUInteger)idx1
            withValueAtIndex:(NSUInteger)idx2;
- (void)insertValue:()value atIndex:(NSUInteger)count;
- (void)replaceValueAtIndex:(NSUInteger)index withValue:()value;


@end

GPBEnumArray has a slightly different interface to handle the validation function and to access raw values.
GPBEnumArray有一个稍微不同的接口,来处理可用验证函数和访问原始值。

@interface GPBEnumArray : NSObject 
@property (nonatomic, readonly) NSUInteger count;
@property (nonatomic, readonly) GPBEnumValidationFunc validationFunc;

+ (instancetype)array;
+ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                   rawValue:value;
+ (instancetype)arrayWithValueArray:(GPBEnumArray *)array;
+ (instancetype)arrayWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                   capacity:(NSUInteger)count;

- (instancetype)initWithValidationFunction:
  (nullable GPBEnumValidationFunc)func;

// Initializes the array, copying the values.
- (instancetype)initWithValueArray:(GPBEnumArray *)array;
- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
    values:(const int32_t [])values
    count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                  capacity:(NSUInteger)count;

// These will return kGPBUnrecognizedEnumeratorValue if the value at index
// is not a valid enumerator as defined by validationFunc. If the actual
// value is desired, use the "raw" version of the method.
- (int32_t)valueAtIndex:(NSUInteger)index;
- (void)enumerateValuesWithBlock:
    (void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
- (void)enumerateValuesWithOptions:(NSEnumerationOptions)opts 
    usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;

// These methods bypass the validationFunc to provide access to values
// that were not known at the time the binary was compiled.
- (int32_t)rawValueAtIndex:(NSUInteger)index;

- (void)enumerateRawValuesWithBlock:
    (void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;
- (void)enumerateRawValuesWithOptions:(NSEnumerationOptions)opts 
    usingBlock:(void (^)(int32_t value, NSUInteger idx, BOOL *stop))block;

// If value is not a valid enumerator as defined by validationFunc, these
// methods will assert in debug, and will log in release and assign the value
// to the default value. Use the rawValue methods below to assign
// non enumerator values.
- (void)addValue:(int32_t)value;
- (void)addValues:(const int32_t [])values count:(NSUInteger)count;
- (void)insertValue:(int32_t)value atIndex:(NSUInteger)count;
- (void)replaceValueAtIndex:(NSUInteger)index withValue:(int32_t)value;

// These methods bypass the validationFunc to provide setting of values that
// were not known at the time the binary was compiled.
- (void)addRawValue:(int32_t)rawValue;
- (void)addRawValuesFromEnumArray:(GPBEnumArray *)array;
- (void)addRawValues:(const int32_t [])values count:(NSUInteger)count;
- (void)replaceValueAtIndex:(NSUInteger)index withRawValue:(int32_t)rawValue;
- (void)insertRawValue:(int32_t)value atIndex:(NSUInteger)count;

// No validation applies to these methods.
- (void)removeValueAtIndex:(NSUInteger)count;
- (void)removeAll;
- (void)exchangeValueAtIndex:(NSUInteger)idx1
            withValueAtIndex:(NSUInteger)idx2;

@end
Oneof fields - Oneof字段

Given a message with oneof field definitions:
给定一个包含[oneof]字段定义的message:

message Order {
  oneof OrderID {
    string name = 1;
    int32 address = 2;
  };
  int32 quantity = 3;
};

The protocol buffer compiler generates:
protocol buffer编译器生成:

typedef GPB_ENUM(Order_OrderID_OneOfCase) {
  Order_OrderID_OneOfCase_GPBUnsetOneOfCase = 0,
  Order_OrderID_OneOfCase_Name = 1,
  Order_OrderID_OneOfCase_Address = 2,
};

typedef GPB_ENUM(Order_FieldNumber) {
  Order_FieldNumber_Name = 1,
  Order_FieldNumber_Address = 2,
  Order_FieldNumber_Quantity = 3,
};

@interface Order : GPBMessage
@property (nonatomic, readwrite) Order_OrderID_OneOfCase orderIDOneOfCase;
@property (nonatomic, readwrite, copy, null_resettable) NSString *name;
@property (nonatomic, readwrite) int32_t address;
@property (nonatomic, readwrite) int32_t quantity;
@end

void Order_ClearOrderIDOneOfCase(Order *message);

Setting one of the oneof properties will clear all the other properties associated with the oneof.
设置oneof其中一个属性后其他所有相关属性都会被清理。

_OneOfCase_GPBUnsetOneOfCase will always be equivalent to 0 to allow for easy testing to see if any field in the oneof is set.
_OneOfCase_GPBUnsetOneOfCase总是等效于0,这样可以很容易的检测oneof中的任何字段是否被设置值。

Map Fields - Map字段

For this message definition:
message定义:

message Bar {...}
message Foo {
  map a_map = 1;
  map b_map = 2;
};

The compiler generates the following:
编译器生成如下:

typedef GPB_ENUM(Foo_FieldNumber) {
  Foo_FieldNumber_AMap = 1,
  Foo_FieldNumber_BMap = 2,
};

@interface Foo : GPBMessage
// Map names are the camel case version of the field name.
@property (nonatomic, readwrite, strong, null_resettable) GPBInt32ObjectDictionary *aMap;
@property(nonatomic, readonly) NSUInteger aMap_Count;
@property (nonatomic, readwrite, strong, null_resettable) NSMutableDictionary *bMap;
@property(nonatomic, readonly) NSUInteger bMap_Count;
@end

Cases where keys are strings and values are strings, bytes, or messages are handled by NSMutableDictionary.
键是string,值是string、byte或message的情况,由NSMutableDictionary处理。

Other cases are:
其他情况:

GBPDictionary

where:

  • is Uint32, Int32, UInt64, Int64, Bool or String.
  • is UInt32, Int32, UInt64, Int64, Bool, Float, Double, Enum, or Object. Object is used for values of type string bytes or message to cut down on the number of classes and is in line with how Objective-C works with NSMutableDictionary.
    是 UInt32, Int32, UInt64, Int64, Bool, Float, Double, Enum或 Object。Object用于类型为string bytesmessage的值以减少类的数量,并且符合
    Objective-C与NSMutableDictionary的工作方式。

Default values - 默认值

The default value for a map field is empty. In Objective-C generated code, this is an empty GBPDictionary. If you access an empty map field, you'll get back an empty dictionary that you can update like any other map field.
map字段的默认值是空。在Objective-C生成的代码中,这是一个空的GBPDictionary。如果你访问一个空的map字段, 你会得到一个空的字典对象,你可以像其他map字段一样更新它。

You can also use the provided property to check if a particular map is empty:
你也可以使用提供的 属性来检测特定map是否为空。

if (myFoo.myMap_Count) {
  // There is something in the map...
}
GBPDictionary interface - GBPDictionary接口

The GBPDictionary (apart from GBPObjectDictionary and GBPEnumDictionary) interface is as follows:
GBPDictionary(除了GBPObjectDictionary 和 GBPEnumDictionary)接口如下:

@interface GPBDictionary : NSObject 
@property (nonatomic, readonly) NSUInteger count;

+ (instancetype)dictionary;
+ (instancetype)dictionaryWithValue:(const )value 
                             forKey:(const )key;
+ (instancetype)dictionaryWithValues:(const  [])values 
                             forKeys:(const  [])keys 
                               count:(NSUInteger)count;
+ (instancetype)dictionaryWithDictionary:(GPBDictionary *)dictionary;
+ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;

- (instancetype)initWithValues:(const  [])values 
                       forKeys:(const  [])keys 
                         count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithDictionary:(GPBDictionary *)dictionary;
- (instancetype)initWithCapacity:(NSUInteger)numItems;

- (BOOL)valueForKey:()key value:(VALUE *)value;

- (void)enumerateKeysAndValuesUsingBlock:
    (void (^)( key,  value, BOOL *stop))block;

- (void)removeValueForKey:()aKey;
- (void)removeAll;
- (void)setValue:()value forKey:()key;
- (void)addEntriesFromDictionary:(GPBDictionary *)otherDictionary;
@end
The GBPObjectDictionary interface is:

GBPObjectDictionary接口:

@interface GPBObjectDictionary : NSObject 
@property (nonatomic, readonly) NSUInteger count;

+ (instancetype)dictionary;
+ (instancetype)dictionaryWithObject:(id)object 
                             forKey:(const )key;
+ (instancetype)
  dictionaryWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects 
                forKeys:(const  [])keys 
                  count:(NSUInteger)count;
+ (instancetype)dictionaryWithDictionary:(GPBObjectDictionary *)dictionary;
+ (instancetype)dictionaryWithCapacity:(NSUInteger)numItems;

- (instancetype)initWithObjects:(const id GPB_UNSAFE_UNRETAINED [])objects 
                        forKeys:(const  [])keys 
                          count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithDictionary:(GPBObjectDictionary *)dictionary;
- (instancetype)initWithCapacity:(NSUInteger)numItems;

- (id)objectForKey:(uint32_t)key;

- (void)enumerateKeysAndObjectsUsingBlock:
    (void (^)( key, id object, BOOL *stop))block;

- (void)removeObjectForKey:()aKey;
- (void)removeAll;
- (void)setObject:(id)object forKey:()key;
- (void)addEntriesFromDictionary:(GPBObjectDictionary *)otherDictionary;
@end

GBPEnumDictionary has a slightly different interface to handle the validation function and to access raw values.
GBPEnumDictionary有一个稍微不同的接口来处理验证函数和访问原始值。

@interface GPBEnumDictionary : NSObject 

@property(nonatomic, readonly) NSUInteger count;
@property(nonatomic, readonly) GPBEnumValidationFunc validationFunc;

+ (instancetype)dictionary;
+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func;
+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                        rawValue:(int32_t)rawValue
                                          forKey:(_t)key;
+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                       rawValues:(const int32_t [])values
                                         forKeys:(const _t [])keys
                                           count:(NSUInteger)count;
+ (instancetype)dictionaryWithDictionary:(GPBEnumDictionary *)dictionary;
+ (instancetype)dictionaryWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                        capacity:(NSUInteger)numItems;

- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func;
- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                 rawValues:(const int32_t [])values
                                   forKeys:(const _t [])keys
                                     count:(NSUInteger)count NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithDictionary:(GPBEnumDictionary *)dictionary;
- (instancetype)initWithValidationFunction:(nullable GPBEnumValidationFunc)func
                                  capacity:(NSUInteger)numItems;

// These will return kGPBUnrecognizedEnumeratorValue if the value for the key
// is not a valid enumerator as defined by validationFunc. If the actual value is
// desired, use "raw" version of the method.

- (BOOL)valueForKey:(_t)key value:(nullable int32_t *)value;

- (void)enumerateKeysAndValuesUsingBlock:
    (void (^)(_t key, int32_t value, BOOL *stop))block;

// These methods bypass the validationFunc to provide access to values that were not
// known at the time the binary was compiled.

- (BOOL)valueForKey:(_t)key rawValue:(nullable int32_t *)rawValue;

- (void)enumerateKeysAndRawValuesUsingBlock:
    (void (^)(_t key, int32_t rawValue, BOOL *stop))block;

- (void)addRawEntriesFromDictionary:(GPBEnumDictionary *)otherDictionary;

// If value is not a valid enumerator as defined by validationFunc, these
// methods will assert in debug, and will log in release and assign the value
// to the default value. Use the rawValue methods below to assign non enumerator
// values.

- (void)setValue:(int32_t)value forKey:(_t)key;

// This method bypass the validationFunc to provide setting of values that were not
// known at the time the binary was compiled.
- (void)setRawValue:(int32_t)rawValue forKey:(_t)key;

// No validation applies to these methods.

- (void)removeValueForKey:(_t)aKey;
- (void)removeAll;

@end

Enumerations - 枚举

Given an enum definition like:
给定一个枚举定义,如:

enum Foo {
  VALUE_A = 0;
  VALUE_B = 1;
  VALUE_C = 5;
}

the generated code will be:
生成的代码:

// The generated enum value name will be the enumeration name followed by
// an underscore and then the enumerator name converted to camel case.
// GPB_ENUM is a macro defined in the Objective-C Protocol Buffer headers
// that enforces all enum values to be int32 and aids in Swift Enumeration
// support.
typedef GPB_ENUM(Foo) {
  Foo_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, //proto3 only
  Foo_ValueA = 0,
  Foo_ValueB = 1;
  Foo_ValueC = 5;
};

// Returns information about what values this enum type defines.
GPBEnumDescriptor *Foo_EnumDescriptor();

Each enumeration has a validation function declared for it:
每个枚举都有一个已声明的验证函数:


// Returns YES if the given numeric value matches one of Foo's
// defined values (0, 1, 5).
BOOL Foo_IsValidValue(int32_t value);

and an enumeration descriptor accessor function declared for it:
和一个已声明的枚举描述访问器函数:

// GPBEnumDescriptor is defined in the runtime and contains information
// about the enum definition, such as the enum name, enum value and enum value
// validation function.
typedef GPBEnumDescriptor *(*GPBEnumDescriptorAccessorFunc)();

The enum descriptor accessor functions are C functions, as opposed to methods on the enumeration class, because they are rarely used by client software. This will cut down on the amount of Objective-C runtime information generated, and potentially allow the linker to deadstrip them.
枚举描述访问器函数是C函数,和枚举类内的方法相反,因为客户端软件很少使用他们。这会减少Objective-C运行时信息生成的数量,并肯能允许连接器删除他们。

In the case of outer enums that have names matching any C/C++ or Objective-C keywords, such as:
与任何C/C++或者Objective-C关键字匹配的外部枚举的情况,比如:

enum method {}

the generated interfaces are suffixed with _Enum, as follows:
生成的接口会以_Enum为后缀,如下:

// The generated enumeration name is the keyword suffixed by _Enum.
typedef GPB_ENUM(Method_Enum) {}

An enum can also be declared inside another message. For example:
一个枚举也可以声明在其他message内部,举例:

message Foo {
  enum Bar {
    VALUE_A = 0;
    VALUE_B = 1;
    VALUE_C = 5;
  }
  Bar aBar = 1;
  Bar aDifferentBar = 2;
  repeated Bar aRepeatedBar = 3;
}

generates
生成

typedef GPB_ENUM(Foo_Bar) {
  Foo_Bar_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue, //proto3 only
  Foo_Bar_ValueA = 0;
  Foo_Bar_ValueB = 1;
  Foo_Bar_ValueC = 5;
};

GPBEnumDescriptor *Foo_Bar_EnumDescriptor();

BOOL Foo_Bar_IsValidValue(int32_t value);

@interface Foo : GPBMessage
@property (nonatomic, readwrite) Foo_Bar aBar;
@property (nonatomic, readwrite) Foo_Bar aDifferentBar;
@property (nonatomic, readwrite, strong, null_resettable)
 GPBEnumArray *aRepeatedBarArray;
@end

// proto3 only Every message that has an enum field will have an accessor function to get
// the value of that enum as an integer. This allows clients to deal with
// raw values if they need to.
int32_t Foo_ABar_RawValue(Foo *message);
void SetFoo_ABar_RawValue(Foo *message, int32_t value);
int32_t Foo_ADifferentBar_RawValue(Foo *message);
void SetFoo_ADifferentBar_RawValue(Foo *message, int32_t value);

All enumeration fields have the ability to access the value as a typed enumerator (Foo_Bar in the example above), or, if using proto3, as a raw int32_t value (using the accessor functions in the example above). This is to support the case where the server returns values that the client may not recognize due to the client and server being compiled with different versions of the proto file.
所有的枚举字段都能够访问作为类型枚举器(上边例子中的Foo_Bar)的值,或者如果用的是proto3,则作为原始int32_t值(上边例子中使用访问器函数)。这是为了支持由于客户端和服务器编译不同版本的proto文件导致客户端无法识别服务器返回值的情况。

Unrecognized enum values are treated differently depending on which protocol buffers version you are using. In proto3, kGPBUnrecognizedEnumeratorValue is returned for the typed enumerator value if the enumerator value in the parsed message data is not one that the code reading it was compiled to support. If the actual value is desired, use the raw value accessors to get the value as an int32_t. If you are using proto2, unrecognized enum values are treated as unknown fields.
无法识别的枚举值根据你所使用的protocol buffer版本进行不同处理。
在 proto3 中,如果解析的消息数据中的枚举值不是编译它的代码读取所支持的值,则为类型化的枚举值返回 kGPBUnrecognizedEnumeratorValue。如果实际值是想要的,使用原始值访问器获得其int32_t值。如果你使用的是proto2,未识别的枚举值会被处理为未识别字段。

kGPBUnrecognizedEnumeratorValue is defined as 0xFBADBEEF, and it will be an error if any enumerator in an enumeration has this value. Attempting to set any enumeration field to this value is a runtime error. Similarly, attempting to set any enumeration field to an enumerator not defined by its enumeration type using the typed accessors is a runtime error. In both error cases, debug builds will cause an assertion and release builds will log and set the field to its default value (0).
kGPBUnrecognizedEnumeratorValue定义为0xFBADBEEF,如果枚举中的任何枚举器拥有此值会报错。尝试将任何枚举字段设置为该值会导致运行时错误。类似的,尝试使用类型访问器将任何枚举类型设置为该枚举类型中未定义的枚举器会导致运行时错误。在这两种错误情况种,debug模式会触发断言而relase模式下会打印日志并将字段值设为默认值(0)。

The raw value accessors are defined as C functions instead of as Objective-C methods because they are not used in most cases. Declaring them as C functions cuts down on wasted Objective-C runtime information and allows the linker to potentially dead strip them.
原始数据访问器定义为C函数而不是Objective-C方式,是因为大多数情况下用不到。声明其为C函数来减少Objective-C运行时信息浪费,并且允许连接器潜在地删除它们。

Swift Enumeration Support - Swift枚举支持

Apple documents how they import Objective-C enumerations to Swift enumerations in Interacting with C APIs. Protocol buffer-generated enumerations support Objective-C to Swift conversions.
Apple在与C APIs交互中记录了他们如何将Objective-C枚举导入到Swift枚举中。Protocol buffer生成的枚举支持Objective-C到Swift的转换。

// Proto
enum Foo {
  VALUE_A = 0;
}

generates:
生成:

// Objective-C
typedef GPB_ENUM(Foo) {
  Foo_GPBUnrecognizedEnumeratorValue = kGPBUnrecognizedEnumeratorValue,
  Foo_ValueA = 0,
};

which in Swift code will allow:
在Swif代码中允许这样:

// Swift
let aValue = Foo.ValueA
let anotherValue: Foo = .GPBUnrecognizedEnumeratorValue

Well-known types (proto3 only) - 已知类型(仅proto3)

If you use any of the message types provided with proto3, they will in general just use their proto definitions in generated Objective-C code, though we supply some basic conversion methods in categories to make using them simpler. Note that we do not have special APIs for all well-known types yet, including Any (there is currently no helper method to convert an Any's message value into a message of the appropriate type).
如果您使用 proto3 提供的任何消息类型,它们通常只会在生成的 Objective-C 代码中使用它们的 proto 定义,尽管我们在类别中提供了一些基本的转换方法以简化它们的使用。注意我们还没有提供为所有已知类型提供特殊APIs,包括Any(目前没有帮助方法来将一个Any消息值转换为一个合适消息类型)

Time Stamps - 时间戳
@interface GPBTimeStamp (GPBWellKnownTypes)
@property (nonatomic, readwrite, strong) NSDate *date;
@property (nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
- (instancetype)initWithDate:(NSDate *)date;
- (instancetype)initWithTimeIntervalSince1970:
    (NSTimeInterval)timeIntervalSince1970;
@end
Duration - 间隔
@interface GPBDuration (GPBWellKnownTypes)
@property (nonatomic, readwrite) NSTimeInterval timeIntervalSince1970;
- (instancetype)initWithTimeIntervalSince1970:
    (NSTimeInterval)timeIntervalSince1970;
@end

Extensions (proto2 only) - 扩展(仅proto2)

Given a message with an extension range:
给定一个拥有扩展范围的message:

message Foo {
  extensions 100 to 199;
}

extend Foo {
  optional int32 foo = 101;
  repeated int32 repeated_foo = 102;
}

message Bar {
  extend Foo {
    optional int32 bar = 103;
    repeated int32 repeated_bar = 104;
  }
}

The compiler generates the following:
编译器生成如下:


# File Test2Root

@interface Test2Root : GPBRootObject

// The base class provides:
//   + (GPBExtensionRegistry *)extensionRegistry;
// which is an GPBExtensionRegistry that includes all the extensions defined by
// this file and all files that it depends on.

@end

@interface Test2Root (DynamicMethods)
+ (GPBExtensionDescriptor *)foo;
+ (GPBExtensionDescriptor *)repeatedFoo;
@end

# Message Foo

@interface Foo : GPBMessage

@end

# Message Bar

@interface Bar : GPBMessage

@end

@interface Bar (DynamicMethods)

+ (GPBExtensionDescriptor *)bar;
+ (GPBExtensionDescriptor *)repeatedBar;
@end

To get and set these extension fields, you use the following:
为了获取和设置这些扩展字段,你可以使用如下方式:

Foo *fooMsg = [[Foo alloc] init];

// Set the single field extensions
[fooMsg setExtension:[Test2Root foo] value:@5];
NSAssert([fooMsg hasExtension:[Test2Root foo]]);
NSAssert([[fooMsg getExtension:[Test2Root foo]] intValue] == 5);

// Add two things to the repeated extension:
[fooMsg addExtension:[Test2Root repeatedFoo] value:@1];
[fooMsg addExtension:[Test2Root repeatedFoo] value:@2];
NSAssert([fooMsg hasExtension:[Test2Root repeatedFoo]]);
NSAssert([[fooMsg getExtension:[Test2Root repeatedFoo]] count] == 2);

// Clearing
[fooMsg clearExtension:[Test2Root foo]];
[fooMsg clearExtension:[Test2Root repeatedFoo]];
NSAssert(![fooMsg hasExtension:[Test2Root foo]]);
NSAssert(![fooMsg hasExtension:[Test2Root repeatedFoo]]);

你可能感兴趣的:(Protocol Buffers:Objective-C Reference)