干活中需求动用protocol
buffer,须求编写翻译出protocol
buffer的动态链接库,然后在别的makefile中链接它,

翻译自:Introduction to Protocol Buffers on
iOS

下载并编写翻译Protocol Buffer

那份教程为C++开荒者提供了动用 Protocol Buffer
的大旨介绍。通过创办多个简短利用,它显得了

  • .proto 文件中定义音信格式。
  • 使用 Protocol Buffer 编译器。
  • 使用C++ Protocol Buffer API读写新闻。

那不是1个在C++中使用 Protocol Buffer
的周到指南。越来越多详细的音讯,请参见Protocol
Buffer语言指南,
C++
API参考,C++
Generated Code
Guide,和
编码参考。

翻译查阅外网资料进度中相遇的比较优异的稿子和素材,壹是用作才干参考以便日后查阅,2是磨炼英文技巧。

此文翻译自 Protocol Buffers 官方文书档案 Protocol Buffer Basics: C++
部分

翻译为意译,不会不能灵活运用的字字对照翻译以下为原著内容翻译

本人的条件是ubnutu1陆.0四,6四bit,使用的protocol buffer 版本是v3.5

对诸多的使用而言,后台服务、传输和积攒数据都是个入眼的模块。开辟者在给一个web service 写接口时,平时采纳 JSON 或许 XML
来发送和接收数据,然后依照那些数量变化结构并分析。

怎么使用Protocol Buffers?

大家将运用的事例是一个万分简单的 “address book”
应用,它能够从文件读取和向文件写入人们的联络人详细的情况。地址簿中的每一种人存有三个名字
(name),ID,电子邮件地址 (email address),和联系人电话号码 (contact
phone)。

您要如何种类化和领取那样的结构化数据吧?有局地措施能够化解这几个主题材料:

  • 原来的内部存款和储蓄器数据结构能够以2进制的款型发送/保存。随着时光的蹉跎,那是1种脆弱的不贰秘籍,因为接受/读取的代码必须以完全同样的内部存储器布局、尾端等等编写翻译。别的,随着文件以本来面目的格式积存数据及管理那种格式的软件的复制,这种格式被持续传来,则它是尤其不便扩展的格式。

  • 您能够表贝因美(Beingmate)(Beingmate)种尤其的法子来将数据项编码编码为三个字符串 ——
    例如将6个int值编码为”1二:叁:-二3:陆七”。那是八个简易而灵活的主意,就算它供给编写制定2次性的编码和剖析代码,而且解析消耗一小段运营时期价。这对于编码相当轻易的数额是最棒的艺术。
    将数据系列化为XML。那种办法大概13分具备吸重力,因为XML是 (有点)
    人类可读的,而且它有雅量编制程序语言的bindings库。若是您想要与任何的施用/项目共享数据来讲,那可能是二个很好的选择。但是,XML是臭名昭著的上空密集,而且编码/解码它需求消耗应用多量的质量开支。而且,浏览二个XML
    DOM树也被以为比一般浏览类中的轻易字段更复杂。

Protocol buffers 是缓和这几个标题灵活,高效,自动化的方案。通过
Protocol buffers ,你能够编写1个 .proto
描述您想要存款和储蓄的数据结构。通过它, Protocol buffers
编写翻译器成立3个类,以一种高效的二进制格式实现机关的编码和平解决析 Protocol
buffers
数据。生成的类为组合八个 Protocol buffers
的字段提供了getters和setters方法,并管理读取和写入 Protocol buffers
的细节。重要地是, Protocol buffers
格式通过使代码依旧能够读取用老的格式编码的数码来支持随着年华对格式的扩大。

本学科为 C++ 程序员如何行使 protocol buffers
做贰个中坚介绍。通过创办2个轻松易行的示范应用程序,它向你显得:

首先大家必要下载protocol
buffer源码,然后依据教程进行设置:

就算有大气的 API
和框架扶助我们体系化和反体系化,来帮忙部分后台接口开荒的常备工作,举个例子说更新代码可能解析器来帮衬后台的模子变化。

在哪儿能够找到示例代码

源码包中富含的言传身教代码,在”examples”
目录下。在那边下载。

  • 什么在二个 .proto 文件中定义 message
  • 哪些运用 protocol buffer 编写翻译器
  • 怎么选取 C++ protocol buffer 的 API 读写 message

参考目录:

可是只要你真正想升官你的新类型的健壮性的话 ,考虑下用 protocol
buffers,它是由
Google开辟用来种类化数据结构的1种跨语言的章程。在重重场合下,它比守旧的 JSON
和 XML
越来越灵活有效。其中一个重中之重的性状就是,你只须要在其帮助的此外语言和编写翻译器下,定义贰回数据结构——包涵Swift! 成立的类公事就足以很自在的读写成靶子。

概念你的协商格式

为了创设你的地址簿应用,你供给先创立一个 .proto 文件。 .proto
文件中的定义很简单:为各种你想要连串化的数据结构增添1个 消息(message)
,然后为新闻中的各样字段内定三个名字和等级次序。那里是概念你的新闻的 .proto
文件,addressbook.proto。

package tutorial;

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

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    required string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phone = 4;
}

message AddressBook {
  repeated Person person = 1;
}

如您所见,语法与C++或Java类似。让大家看一下以此文件的每种部分,并看一下它做了如何。

.proto
文件以三个包表明早先,那用于幸免不相同品种间的命名争辩。在C++中,生成的类将被停放在与包名相配的命名空间中。

接下去,定义你的音信。新闻只是带有了全体类型的字段的集纳。很多规范的简要数据类型可用作字段类型,包蕴bool,int3二,float,double,和string。你也足以经过利用音讯类型作为字段类型来给您的音信增加越来越多组织——
在上边包车型大巴事例中,Person新闻包蕴了八个PhoneNumber音讯,同时AddressBook音信包蕴Person音讯。你居然能够在别的新闻中嵌套的概念信息类型
——
如您所见,PhoneNumber类型是在Person中定义的。假如你想要你的字段值为某些预约义的值列表中的有些值的话,你也得以定义enum类型
—— 那里你想要钦定电话号码是MOBILE,HOME,或WO君越K中的八个。

各样成分上的 ” = 1″,” = 2″标志标志在2进制编码中使用的该字段唯①的
“tag” 。Tag数字 一-一五比越来越大的数字在编码上少叁个字节,因此作为壹种优化,你可以调节将那么些数字用作常用的或再度的成分的tag,而将16及更加大的数字tag留给越发不常用的可选成分。重复字段中的每一个成分需求重编码tag数字,因此这种优化尤其适用于重新字段。

每一个字段必须用上边包车型地铁修饰符中的二个来讲解:

  • required:字段必须提供,不然音讯将被感觉是 “未伊始化的
    (uninitialized)”。假诺libprotobuf以debug情势编写翻译,则连串化未发轫化的新闻将促成断言败北。在优化的打造中,检查将被跳过,新闻仍将被写入。然则,解析未先河化的音讯将连接失败(通过喜爱parse方法中回到false)。不然,required字段的一颦一笑将与optional字段完全一样。

  • optional:字段能够设置也能够不设置。就算可选的字段值未有安装,则将接纳暗中同意值。对于简易的品类,你能够钦定你和睦的暗许值,如大家在例子中为电话号码类型做的那么。不然,将采纳系统私下认可值:数字类型为0,字符串类型为空字符串,bools值为false。对于内嵌的信息,私下认可值总是音讯的
    “私下认可实例 (default instance)” 或
    “原型(prototype)”,它们并没有自个儿的字段集。调用accessor获取还尚未显式地安装的
    optional (或required) 字段的值总是回到字段的暗许值。

  • repeated:字段能够重复任性数次 (蕴含0)。在 protocol buffer
    中,重复值的壹一将被保存。将再度字段想象为动态大小的数组。

您将找到3个编纂 .proto 文件的全部指南 —— 包涵富有希望的字段类型 ——
在Protocol Buffer Language
Guide
一文中。不要寻觅与类承继类似的设施 —— protocol buffer 不那么做。

那不是一篇通过 C ++ 使用 protocol
的汇总指南。要是想获得更详细的参阅新闻,请参阅 Protocol Buffer
语法指导、C++ API 引导、C++ 生成代码指引 和 Protocol Buffer 的
编码教导。

设置步骤:

在那篇教程中,会动用一个 Python 服务端与二个 iOS 程序交互。你会学到
protocol buffers 是咋办事,如何布署碰着,最后怎么使用 protocol buffers
传输数据。

编写翻译你的Protocol Buffers

近来您有了贰个.proto,接下去你需求做的事情是生成读写 AddressBook
(及Person 和 PhoneNumber) 音信所需的类。要成功那点,你须要在你的
.proto 上运维 Protocol Buffers 编译器protoc:

  1. 壹旦您还尚未安装编写翻译器,则下载包,并根据README的指令举行。

  2. 今昔运行编写翻译器,钦定源目录 (放置你的利用程序源代码的地点 ——
    假如您未曾提供则运用当前目录),目标目录
    (你希望放置生成的代码的地方;平日与$S奥迪Q3C_DIPRADO同样),你的.proto的渠道。在那几个例子中,你…

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto

是因为您想要C++类,所以使用 –cpp_out 选项 ——
也为别的帮忙的言语提供了近乎的选项。

那将要您钦定的目的目录下生成上面包车型地铁文本:

  • addressbook.pb.h,注解你的生成类的头文件。
  • addressbook.pb.cc,包罗了您的类的贯彻。

大家就要选用的言传身教是1个极度轻巧的 “地址簿”
应用程序,能够在文书中读写联系人的详细音信。地址簿中的种种人都有姓名、ID、电子邮件地址和联系电话。

$ sudo apt-get install autoconf automake libtool curl make g++ unzip
$ ./autogen.sh
$ ./configure
$ make
$ make check
$ sudo make install
$ sudo ldconfig # refresh shared library cache.

怎么,依然不相信 protocol buffers 就是您所急需的事物?接着往下读吧。

Protocol Buffer API

让我们看一下生成的代码,并看一下编写翻译器都为您创设了怎么着类和函数。即使翻开tutorial.pb.h,你能够看看您在tutorial.proto中讲述的各样音信都有二个类。进一步看Person类的话,你能够观察编写翻译器已经为各样字段生成了accessors。比方,name,id,email,和phone字段,你抱有这一个主意:

 // name
 inline bool has_name() const;
 inline void clear_name();
 inline const ::std::string& name() const;
 inline void set_name(const ::std::string& value);
 inline void set_name(const char* value);
 inline ::std::string* mutable_name();

 // id
 inline bool has_id() const;
 inline void clear_id();
 inline int32_t id() const;
 inline void set_id(int32_t value);

 // email
 inline bool has_email() const;
 inline void clear_email();
 inline const ::std::string& email() const;
 inline void set_email(const ::std::string& value);
 inline void set_email(const char* value);
 inline ::std::string* mutable_email();

 // phone
 inline int phone_size() const;
 inline void clear_phone();
 inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phone() const;
 inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phone();
 inline const ::tutorial::Person_PhoneNumber& phone(int index) const;
 inline ::tutorial::Person_PhoneNumber* mutable_phone(int index);
 inline ::tutorial::Person_PhoneNumber* add_phone();

如您所见,getters的名字与字段名的小写格局完全平等,而setter方法则以set_起先。每一种单数的
(required 或 optional) 字段还有has_
方法,如果那三个字段已经棉被服装置了则它们放回true。最终,每一个字段具备2个clear_ 方法,用于将字段设置回它的空状态。

数字的id字段唯有基本的看来的accessor
set,而name和email字段则有1对额外的措施,因为它们是字符串 ——
贰个mutable_
getter,让你取得指向字符串的一向的指针,及一个异常的setter。注意你能够调用mutable_email(),即便email还从未设置;它将被活动地伊始化为3个空字符窜。借使在那么些事例中您有多个单数的新闻字段,它将还有三个mutable_方法,而没有set_方法。

双重的字段还有一些专程的主意 ——
如若您查正视复的phone字段的法门的话,你将见到你能够

  • 检查重复字段的 _size
    (换句话说,与这么些Person关联的电话号码某些许个)。
  • 运用索引获得一个一定的电话号码。
  • 更新特定岗位处的已有电话号码。
  • 给新闻加多另贰个后边你能够编写的电话号码
    (重复的标量类型具备1个add_ 以使你可以流传新值)。

有关protocol编写翻译器为其余特定的字段定义爆发什么样成员的越来越多新闻,请参考
C++
生成代码参考。

你该怎么体系化和反系列化如上组织的数额吧?那里有二种缓慢解决方案:

里头必要留意的地方,安装软件的时候,或者出现停业的标题,建议将ubnutu软件源改为阿里Baba(Alibaba)的源或许博客园的源,具体操作方法请百度。

只顾:那篇教程是依靠你已经有了迟早的 iOS 和 Swift经验,同时有必然的基本的服务端和 terminal 基础。
并且,确认保障您利用的是苹果的 Xcode 八.2或之后的版本.

枚举和嵌套类

改造的代码包涵1个PhoneType枚举,它对应于您的.proto枚举。你能够以Person::PhoneType引用这几个类别,它的值包罗Person::MOBILE,Person::HOME,和Person::WOEnclaveK
(落成细节要复杂一点,但您利用枚举时无需清楚它们)。

编写翻译器还为你生成了号称Person::PhoneNumber的嵌套类。假若您看代码,会意识
“真实的” 类实际称为
Person_PhoneNumber,但定义在Person内的typedef使您能够像2个嵌套类同样采取它。会潜移默化到的仅局地景况是,倘若你想要在另贰个文书中前向申明类
—— 你无法在C++中前向注脚嵌套类型,但您可从前向申明Person_PhoneNumber。

  • 能够以2进制方式发送/保存原有内部存款和储蓄器中数据结构。随着年华的延期,这是一种脆弱的主意,因为接受/读代替码必须选拔完全同样的内部存储器布局、字节顺序等展开编写翻译。其它,由于文件以原始格式积存数据,并且解析该格式的软件别本四处扩散,由此很难扩充格式。

  • 您能够发美赞臣种特有的办法将数据项编码为单个字符串 – 比如将 6个整数编码为
    “12:三:-贰三:67″。那是1种简易而灵活的章程,尽管它实在须要编写制定3回性编码和剖析的代码,并且解析会发出部分小的周转时基金。但那相当适合格外轻巧的数据的编码。

  • 将数据类别化为 XML。那种艺术丰裕有魔力,因为
    XML是人类可读的,并且有成都百货上千言语的绑定库。假诺你想与其他应用程序/项目共享数据,这说不定是三个毋庸置疑的抉择。不过,XML
    是醒目要求愈来愈多的空间,并且编码/解码 XML
    会对应用程序造成巨大的属性损失。别的,导航 XML DOM
    树比一般在类中导航轻巧字段要复杂得多。

接下来那里要注意curl
和libcurl版本要1如既往,不然./autogen.sh的时候会报错。

安不忘危早先

RWCards那个应用软件可以用来查看你的议会门票和演讲者名单。下载Starter
Project并张开根目录Starter。先了解一下那上边那三片段:

标准的音信方法

各个音讯类还富含大量的别的方法,来让您检查或管理整个音信,包含:

  • bool IsInitialized() const;:
    检查是不是持有的required字段都已经被安装了。
  • string DebugString() const;:
    重返一人类可读的音讯表示,对调整尤其有用。
  • void CopyFrom(const Person& from);: 用给定消息的值覆写音信。
  • void Clear();: 清空全数的因素为空状态。

那个办法以及在后头的小节中描述的I/O方法达成了富有C++ protocol
buffer类共享的Message接口。更多音讯,请参考
Message的完整API文档。

而 Protocol buffers 是灵活,高效,自动化的缓慢解决方案。接纳 protocol
buffers,你能够写1个 .proto 文件讲述您想要读取的数码的布局。因此,
protocol buffer 编写翻译器将创建七个类,该类应用有效的贰进制格式实现protocol buffer 数据的自动编码和分析。生成的类为组合 protocol buffer
的字段提供 getter 和 setter,并承担读写 protocol buffer
单元的细节。主要的是,protocol buffer
的格式帮助随着时光的延迟扩大格式的主见,使得代码依旧能够读取用旧格式编码的数额。

末尾生成的库如下: 

The Client

Starter/RWCards下,打开
RWCards.xcworkspace,大家来探视那多少个重大的公文:

  • SpeakersListViewController.swift
    管理了1个用来显示演讲者名单的table
    view。这一个调节器未来还只是个模板因为您还未曾为其创制模型。
  • SpeakersViewModel.swift 相当于 SpeakersListViewController
    的数据源,它会含有有解说者的花名册数据。
  • CardViewController.swift 用来显示参会者的名片和她的张罗音讯.
  • RWService.swift 管理客户端和后端的交互。你大概会用到
    法定文档,中的使用。Alamofire 来发起服务请求。
  • Main.storyboard 整个 APP 的 storyboard.

全总工程师程采用
CocoaPods
来拉取那七个框架:

  • Swift
    Protobuf
    支持在 Xcode 中使用 Protocol Buffers.
  • Alamofire
    1个 HTTP 网络库,你会用到它来呼吁服务器。

留神:那篇教程中你会用到 Swift Protobuf 0.9.二4 和 谷歌(Google)’s Protoc
Compiler 三.一.0. 它们曾经打包在品种里了,所以你不要求再做别的。

Parsing and Serialization解析和连串化

最终,每一种protocol buffer类都有应用protocol buffer
贰进制格式写和读你所采用项目标音讯的主意。这一个主意包罗:

  • bool SerializeToString(string* output) const;:
    连串化音讯并将字节存款和储蓄进给定的字符串中。注意,字节是二进制格式的,而不是文本;大家只将string类用作适当的器皿。
  • bool ParseFromString(const string& data);:
    从给定的字符串解析七个新闻。
  • bool SerializeToOstream(ostream* output) const;:
    将音信写入给定的C++ ostream。
  • bool ParseFromIstream(istream* input);: 从给定的C++
    istream解析音信。

那一个只是分析和体系化提供的有的选用。再一次,请参考 Message API
参考
来得到完整的列表。

示范代码包含在源代码包中的 “examples” 目录下。下载地址

 澳门金沙国际 1

Protocol Buffers 是何许做事的?

始于选取 protocol buffers 前,首先要定义三个 .proto
文件。在那个文件中钦赐了您的数据结构音信。上边是四个 .proto
文件的示范:

syntax = "proto3";

message Contact {

  enum ContactType {
    SPEAKER = 0;
    ATTENDANT = 1;
    VOLUNTEER = 2;
  }

  string first_name = 1;
  string last_name = 2;
  string twitter_name = 3;
  string email = 4;
  string github_link = 5;
  ContactType type = 6;
  string imageName = 7;
};

以此文件里定义了2个 Contact 的 message 和它的有关属性。

.proto 文件定义好了后,你只须要把那一个文件提交 protocol buffer
的编写翻译器,编写翻译器会用你选取的言语创制好2个数据类(斯威夫特 中的
结构)。你能够一贯在项目中应用那个类/结构,非凡轻易!

澳门金沙国际 2

编写翻译器会将 .proto 中的 message
调换到事先选用的语言,并扭转模型对象的源文件。后边会波及定义.proto音讯的更加多细节。
别的在思量 protocol buffers 在此之前,你应有思量它是或不是你项目的极品方案。

写消息

于今让大家试着使用protocol
buffer类。你想要你的地址簿应用能够做的第3件专业是将个人详细情况写入地址簿文件。要成功那或多或少,你必要创建并幸免你的protocol
buffer类的实例,然后将它们写入二个输出流。那里是3个顺序,它从一个文书读取多少个AddressBook,基于用户输入给它加多2个新Person,不分轩轾复将新的AddressBook写回文件。直接调用或引用由protocol编写翻译器生成的代码的有个别都被高亮了。

#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;

// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
  cout << "Enter person ID number: ";
  int id;
  cin >> id;
  person->set_id(id);
  cin.ignore(256, '\n');

  cout << "Enter name: ";
  getline(cin, *person->mutable_name());

  cout << "Enter email address (blank for none): ";
  string email;
  getline(cin, email);
  if (!email.empty()) {
    person->set_email(email);
  }

  while (true) {
    cout << "Enter a phone number (or leave blank to finish): ";
    string number;
    getline(cin, number);
    if (number.empty()) {
      break;
    }

    tutorial::Person::PhoneNumber* phone_number = person->add_phone();
    phone_number->set_number(number);

    cout << "Is this a mobile, home, or work phone? ";
    string type;
    getline(cin, type);
    if (type == "mobile") {
      phone_number->set_type(tutorial::Person::MOBILE);
    } else if (type == "home") {
      phone_number->set_type(tutorial::Person::HOME);
    } else if (type == "work") {
      phone_number->set_type(tutorial::Person::WORK);
    } else {
      cout << "Unknown phone type.  Using default." << endl;
    }
  }
}

// Main function:  Reads the entire address book from a file,
//   adds one person based on user input, then writes it back out to the same
//   file.
int main(int argc, char* argv[]) {
  // Verify that the version of the library that we linked against is
  // compatible with the version of the headers we compiled against.
  GOOGLE_PROTOBUF_VERIFY_VERSION;

  if (argc != 2) {
    cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
    return -1;
  }

  tutorial::AddressBook address_book;

  {
    // Read the existing address book.
    fstream input(argv[1], ios::in | ios::binary);
    if (!input) {
      cout << argv[1] << ": File not found.  Creating a new file." << endl;
    } else if (!address_book.ParseFromIstream(&input)) {
      cerr << "Failed to parse address book." << endl;
      return -1;
    }
  }

  // Add an address.
  PromptForAddress(address_book.add_person());

  {
    // Write the new address book back to disk.
    fstream output(argv[1], ios::out | ios::trunc | ios::binary);
    if (!address_book.SerializeToOstream(&output)) {
      cerr << "Failed to write address book." << endl;
      return -1;
    }
  }

  // Optional:  Delete all global objects allocated by libprotobuf.
  google::protobuf::ShutdownProtobufLibrary();

  return 0;
}

注意GOOGLE_PROTOBUF_VERIFY_VE奥迪Q5SION宏。它是优质的举办 ——
纵然不是从严必须的 —— 在选拔C++ Protocol
Buffer库以前实施那些宏。它注明你未曾奇迹地链接多少个与您编写翻译的头文件版本不合营的库版本。如果探测到版本不包容,程序将告一段落。注意每一个.pb.cc文件自动地在运营时调用那么些宏。

还要注重在先后的末梢调用ShutdownProtobufLibrary()。那一个手续做的所有事务是删除Protocol
Buffer库分配的大局对象。那对多数程序都以不须求的,因为经过退出后,OS将回收它的富有内从。不过,假诺你使用了内部存款和储蓄器泄漏检查工具,它需求各种对象都被保释,大概1旦你在编写3个库,它大概被单独的过程加载和卸载数十次,则你可能想要强制Protocol
Buffers清理全部的东西。

要开创地址簿应用程序,你要求从 .proto 文件伊始。.proto
文件中的定义异常粗略:为要连串化的种种数据结构增加 message 定义,然后为
message 中的每一种字段钦定名称和种类。上边就是定义相关 message 的 .proto
文件,addressbook.proto。

浮动的库文件在/usr/local/lib文件夹下。后边就能够依照自个儿须求采取适合的库文件。

优势

JSON 和 XML 恐怕是眼下开荒者们用来累积和传输数据的行业内部方案,而 protocol
buffers 与之比较有以下优势:

  • 神速且小巧:依据 Google 所讲述的,protocol buffers
    的体量要小3-10倍,速度比XML要快20-100倍。能够在那篇文章
    ,它的撰稿人是 达米恩 Bod,文中相比较了一部分主流文本格式的读写速度。
  • 品类安全:Protocol buffers 像 斯威夫特 同样是种类安全的,使用
    protocol buffers 时 你须求钦定每二个属性的类型。
  • 机关反类别化:你不需求再去编写任何的分析代码,只需求更新
    .proto 文件就行了。
    file and regenerate the data access classes.
  • 享用就是关怀:因为支撑四种语言,因而得以在分裂的平博洛尼亚国共产党享数据模型,那意味跨平台的职业会更轻易。

读消息

当然,假若你无法从地址簿中获取音讯的话,那它就每什么用了。那么些事例读取上面例子创设的文本并打字与印刷它的具备消息。

#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;

// Iterates though all people in the AddressBook and prints info about them.
void ListPeople(const tutorial::AddressBook& address_book) {
  for (int i = 0; i < address_book.person_size(); i++) {
    const tutorial::Person& person = address_book.person(i);

    cout << "Person ID: " << person.id() << endl;
    cout << "  Name: " << person.name() << endl;
    if (person.has_email()) {
      cout << "  E-mail address: " << person.email() << endl;
    }

    for (int j = 0; j < person.phone_size(); j++) {
      const tutorial::Person::PhoneNumber& phone_number = person.phone(j);

      switch (phone_number.type()) {
        case tutorial::Person::MOBILE:
          cout << "  Mobile phone #: ";
          break;
        case tutorial::Person::HOME:
          cout << "  Home phone #: ";
          break;
        case tutorial::Person::WORK:
          cout << "  Work phone #: ";
          break;
      }
      cout << phone_number.number() << endl;
    }
  }
}

// Main function:  Reads the entire address book from a file and prints all
//   the information inside.
int main(int argc, char* argv[]) {
  // Verify that the version of the library that we linked against is
  // compatible with the version of the headers we compiled against.
  GOOGLE_PROTOBUF_VERIFY_VERSION;

  if (argc != 2) {
    cerr << "Usage:  " << argv[0] << " ADDRESS_BOOK_FILE" << endl;
    return -1;
  }

  tutorial::AddressBook address_book;

  {
    // Read the existing address book.
    fstream input(argv[1], ios::in | ios::binary);
    if (!address_book.ParseFromIstream(&input)) {
      cerr << "Failed to parse address book." << endl;
      return -1;
    }
  }

  ListPeople(address_book);

  // Optional:  Delete all global objects allocated by libprotobuf.
  google::protobuf::ShutdownProtobufLibrary();

  return 0;
}
syntax = "proto2";package tutorial;message Person { required string name = 1; required int32 id = 2; optional string email = 3; enum PhoneType { MOBILE = 0; HOME = 1; WORK = 2; } message PhoneNumber { required string number = 1; optional PhoneType type = 2 [default = HOME]; } repeated PhoneNumber phones = 4;}message AddressBook { repeated Person people = 1;}

记得链接改造态库的时候须求充足 -lprotobuf 

局限性

Protocol buffers 即使全部大多优势,可是它也不是万能的:

  • 时间资金财产:在老品种中去行使 protocol buffers
    恐怕会不太高速,因为需求更改费用。同时,项目成员还亟需去读书壹种新的语法。
  • 可读性:XML 和 JSON 的描述性越来越好,并且易于阅读。Protocol buffers
    的原数据不可能阅览,并且在尚未 .proto 文件的事态下不能够解析。
  • 无非是不相符而已:当您想要使用类似于XSLT如此那般的样式表时,XML是最好的精选。所以
    protocol buffers 并不总是最棒工具。
  • 不支持:编写翻译器或者不帮忙你正在张开中的项目所运用的语言和平台。

就算并不是符合于全部的情状,但 protocol buffers
确确实实有着无数的优势。
把程序运维起来试试看呢。

澳门金沙国际 3

噩运的是你未来还看不到任何音信,因为数据源还未有初步化。你要做的是呼吁服务端并且将演说者和参加会议者数据填充到页面上。首先,你相会到项目中提供的:

扩展1个Protocol Buffer

在您发表使用你的protocol buffer的代码之后或早或完,你都将一定的想要
“进步” protocol
buffer的定义。假设你想要你的新buffers向后相当,你的老buffers向前包容 ——
你本来差不多连接想要那样 —— 然后你有部分平整要听从。在新本子的protocol
buffer中:

  • 毫无疑问不能够 修改任何已有字段的tag数字。
  • 一定不可能 增多或删除required字段。
  • 可以 删除可选的或另行的字段。
  • 可以 添加可选或重复的字段,但你必须利用新的tag数字
    (比方,从未在这么些protocol
    buffer中使用过的tag数字,乃至是在剔除的字段中也是)。

(那些规则有
1部分不等
,但它们差不离一贯不选择)

若果你根据那几个规则,老代码将快意地读取新音讯并简要地忽视新字段。对于老代码来说,删除的可选字段将轻易的具备它们的暗中同意值,删除的重复字段将是空的。新代码将透明地读取老音讯。然则,请牢记新的可选字段将不会冒出在老的音信中,因而你将索要出示地检查它们是或不是经过has_设置了,或通过
[default = value] 在您的 .proto
文件中的tag数字背后提供2个靠边的暗许值。假若未有为可选成分钦赐暗许值,则会选拔一定于类型的私下认可值替代:对于字符串,暗中同意值是空字符串。对于booleans,暗中同意值是false。对于数字类型,暗中同意值是0。还要小心即便您增加了一个新的再一次字段,你的新代码将不可能分别他是空的
(通过新代码) 依然根本未有安装 (通过老代码) ,因为它并未有 has_ 标记。

如你所见,语法类似于 C++ 或
Java。让大家浏览文件的每一个部分,看看它们的效果。

Protocol Buffer 模板

Head back to Finder and look inside Starter/ProtoSchema. You’ll see
the following files:
打开 Starter/ProtoSchema 目录,你会看到这一个文件:

  • contact.proto 用 protocol buffer 的语法定义了一个 contact
    的构造。之后会更详尽地证实这些。
  • protoScript.sh 这一个 bash 脚本使用 protocol buffer 的编译器读取
    contact.proto 分别生成了 斯威夫特 和 Python 的数据模型。

优化提出

C++ Protocol
Buffers是由此高度优化了的。但是,适当的施用能够进步越多属性。那里是某些提醒,用于从库中挤出每1滴品质:

  • 设若大概就起用音讯。音信音讯会尝试保留它们分配的内部存款和储蓄器以复用,乃至当它们被清理的时候。这样,如若您在连年处理一样等级次序及类似结构的重重新闻,则每一回复用一样音信对象正是三个降落内部存款和储蓄器分配器负载的好主意。然后,对象大概随着变得膨胀,特别是只要您的消息在
    “形状(shape)”
    上时不时改造,或只要您偶尔构造了多个比常见状态大过多的音信。你应该通过调用
    SpaceUsed
    方法监视你的音讯对象的高低,并在它们变的太大时去除它们。

  • 你的系统的内存分配器恐怕未有对准在拾2线程中分配多量小目的做个很好的优化。则尝试运用
    Google的tcmalloc
    来代替。

.proto 文件以 package 证明初步,那有助于堤防不一致类型里面包车型大巴命名争辩。在
C++ 中,生成的类将放在与包名相称的 namespace 中。

服务端

Starter/Server 目录下包含:

  • RWServer.py
    是放在Flask上的一个Python 服务。包蕴七个 GET 请求:

    • /currentUser 获取当前参加会议者的音讯。
    • /speakers 获取演说者列表。
  • RWDict.py 包含了 RWServer 就要读取的发言者列表数据.

今后是时候配置意况来运维 protocol buffers
了。在下边包车型客车章节中,你会创造好运营 谷歌(Google) 的 protocol
buffer编写翻译器遭逢,Swift 的 Protobuf 插件,并安装 Flask 来运维你的 Python
服务。

高等用法

Protocol buffers的使用意况不仅仅是简单的存取器和连串化。确定保证浏览 C++
API
参考
来精通您还足以用它做怎么样。

由protocol新闻类提供的一个关键意义是 反射
。你能够迭代2个音讯的字段,并在不对准特定的消息类型编写你的代码的场地下,管理它们的值。使用反射的贰个万分实惠的措施是将protocol音信调换为任何编码形式,或从任何编码格局转换,举例XML或JSON。反射的一个更加高档的使用或然是寻找同样等级次序的三个音讯之间的异样,也许支付某种”protocol新闻正则表明式”,你能够编写制定表明式用它非常某1新闻内容。要是运用你想象力,则将Protocol
Buffers用到比你最初梦想的愈来愈广阔的难题的消除中是有希望的!

Message::Reflection
接口提供了反射.

原文

接下去,你将看到有关的 message 定义。message
只是含有壹组项目字段的集合。大多规范的粗略数据类型都可用作字段类型,包罗bool、int3贰、float、double 和 string。你还足以行使此外 message
类型作为字段类型在新闻中增多越来越多组织 – 在上头的言传身教中,Person 包括PhoneNumber message ,而 AddressBook 包涵 Person
message。你居然可以定义嵌套在其余 message 中的 message 类型 -​​
如您所见,PhoneNumber 类型在 Person
中定义。假若您指望当中二个字段具有预订义的值列表中的值,你还足以定义枚举类型

情状布置

在利用 protocol buffers 以前须求设置多数的工具和库。starter
项目中富含了1个名称叫 protoInstallation.sh
的台本帮您解决了那些。它会在安装以前检查是或不是早已设置过这几个库。
本条本子必要花一点时光来设置,尤其是安装 谷歌(Google) 的 protocol buffer
库。展开你的顶峰,cd 命令进入到 Starter 目录试行下边那几个命令:

$ ./protoInstallation.sh

只顾:施行的进度中您可能会被需要输入助理馆员密码。

本子实行到位后,再运维贰遍以保证的到以下输出结果:

澳门金沙国际 4

借使您看到这一个,那表示脚本已经进行完结。假诺脚本施行停业了,那检查下您是还是不是输入了错误的组织者密码。并再次运行脚本;它不会重新安装这几个已经打响的库。
其一本子做了这一个事:

  1. 设置 Flask 以运维 Python 本地服务。
  2. 从 Starter/protobuf-三.壹.0 目录下生成 protocol buffer 编写翻译器。
  3. 设置 protocol buffer 的 Python 模块,那样服务端能够应用 Protobuf
    库。
  4. 将 Swift Protobuf 插件 protoc-gen-swift 移至 /usr/local/bin.
    使 Protobuf 编写翻译器能够生成 Swift 的结构。

只顾:你可以用编辑器展开 protoInstallation.sh
文件来打听这些脚本是怎么行事的。这亟需一定的 bash 基础。

好了,今后你曾经做好了使用 protocol buffers 的有着筹划工作。

  • 此地你钦点电话号码,它的值能够是 MOBILE,HOME 或 WOPAJEROK 之①。

概念三个 .proto 文件

.proto 文件定义了 protocol buffer 描述您的数据结构的
message。把那一个文件中的内容传递给 protocol buffer
编写翻译器后,编写翻译器会转移你的数据结构。

留神:在那篇教程中,你将利用 proto3 来定义 message,那是
protocol buffer 语言的风靡版本。能够访问Google’s
guidelines以博取越多的
proto三 的音讯。

用你最习贯的编辑器张开 ProtoSchema/contact.proto
,那里早已定义好了演说者的 message

syntax = "proto3";

message Contact { // 1

  enum ContactType { // 2
    SPEAKER = 0;
    ATTENDANT = 1;
    VOLUNTEER = 2;
  }

  string first_name = 1; //3
  string last_name = 2;
  string twitter_name = 3;
  string email = 4;
  string github_link = 5;
  ContactType type = 6;
  string imageName = 7;
};

message Speakers { // 4
  repeated Contact contacts = 1;
};

我们来看一下那中间含有了怎么内容:

The Contact model describes a person’s contact information. This will be
displayed on their badges in the app.

  1. Contact 模型用于描述名片信息。在 app 中会被出示在 badges 页。
  2. 每二个 contact 应该分类,这样才具分别出是访客如故解说者。
  3. proto 文件中的每一条 messageenum
    必须派遣1个增量且唯壹的数字标签。那么些数字用来用于区分新闻贰进制格式的,那很重大。访问reserved
    fields能够精通更加多关于标签的信息。
  4. Speakers 模型包括了 contacts 的聚合,* repeated*
    关键字表示贰个对象的数组。

每一个元素上的 “=一”,”=二” 标识表示该字段在二进制编码中选择的绝无仅有
“标记”。标签号 1-1伍比起更加大数字要求少3个字节实行编码,因而那几个实行优化,你能够调节将这一个标签用于常用或重复的因素,将标记1陆 和越来越高的记号留给不太常用的可选成分。repeated
字段中的每种成分都亟需再行编码 Tag,由此 repeated
字段尤其吻合利用此优化。

生成 Swift 结构

contact.proto 传递给 protoc 程序,proto 文件中的 message
将会被转发生成 Swift 的构造。那个结构会遵守 ProtobufMessage.protoc
并提供 斯威夫特 中布局、方法来种类化和反连串化数据的门径。

专注:想打听越来越多关于 斯威夫特 的 protobuf API, 访问苹果的 Protobuf API
documentation.

在顶峰中,进入** Starter/ProtoSchema **目录,用编辑器张开
protoScript.sh,你会看出:

#!/bin/bash
echo 'Running ProtoBuf Compiler to convert .proto schema to Swift'
protoc --swift_out=. contact.proto // 1
echo 'Running Protobuf Compiler to convert .proto schema to Python'
protoc -I=. --python_out=. ./contact.proto // 2

以此本子对 contact.proto 文件试行了三遍 protoc 命令,分别创造了
Swift 和 Python 的源文件。
再次回到终端,实行上边包车型地铁一声令下:

$ ./protoScript.sh

您会晤到以下输出结果:

Running ProtoBuf Compiler to convert .proto schema to Swift
protoc-gen-swift: Generating Swift for contact.proto
Running Protobuf Compiler to convert .proto schema to Python

你早已创办好了 斯维夫特 和 Python 的源文件。
在 ** ProtoSchema** 目录下,你会看到1个 Swift 和三个 Python
文件。同时分别还有二个对应的 .pb.swift.pb.py. pb 前缀表示这是
protocol buffer 生成的类。

澳门金沙国际 5

contact.pb.swift 拖到 Xcode 的 project navigator 下的
Protocol Buffer Objects 组. 勾上“Copy items if needed”选项。同时将
contact_pb2.py 拷贝到 Starter/Server 目录。
看一眼 ** contact.pb.swift** 和 contact_pb2.py中的内容,看看
proto message 是什么样转变来目的语言的。
当今你早已有了生成好的模子对象了,能够开端集成了!

翻译注:“repeated 字段中的各样元素都亟待重新编码 Tag”,指的应该是
string 等门类的 repeated 字段。

运作本地服务器

以身作则代码中带有了一个 Python 服务。这几个服务提供了多个 GET
请求:2个用来获得参加会议者的闻名海外消息,另一个用来列出演说者。
其1课程不会深入讲明服务端的代码。固然如此,你要求领悟到它使用了由
protocol buffer 编写翻译器生成的 contact_pb2.py
模型文件。假设你感兴趣,能够看1看 RWServer.py
中的代码,不看也不要紧(手动滑稽)。
开采终端并 cd 至 Starter/Server 目录,运营上面的吩咐:

$ python RWServer.py

运维结果如下:

澳门金沙国际 6

务必利用以下修饰符之1注释每种字段:

测试 GET 请求

通过在浏览器中倡导 HTTP 请求,你能够见见 protocol buffer 的原数据。
在浏览器中开发
http://127.0.0.1:5000/currentUser
你汇合到:

澳门金沙国际 7

再试试演说者的接口,http://127.0.0.1:5000/speakers

澳门金沙国际 8

在意:测试 帕杰罗WCards app的长河中您能够退出、中止和重启当地服务以便调节和测试。

今后您早就运转了本地服务器,它使用的是由 proto
文件生成的模子,是或不是很cooool?

  • required:
    必须提供该字段的值,不然该新闻将被视为“未开端化”。假设是在调试情势下编写翻译libprotobuf,则种类化一个未起头化的 message
    将将导致断言退步。在优化的塑造中,将跳过检查并一贯写入消息。不过,解析未开始化的消息将始终未果(通过从分析方法返回false)。除了这一个之外,required 字段的一举一动与 optional 字段完全同样。

  • optional:
    可以安装也足以不安装该字段。如若未安装可选字段值,则利用默许值。对于简易类型,你能够内定本人的默许值,仿佛我们在演示中为电话号码类型所做的那么。不然,使用系统私下认可值:数字类型为
    0,字符串为空字符串,bools 为 false。对于嵌入
    message,暗中同意值始终是消息的 “私下认可实例” 或
    “原型”,当中并未有设置任何字段。调用访问器以获得尚未显式设置的
    optional(或 required)字段的值始终再次回到该字段的默许值。

  • repeated: 该字段能够再一次大肆次数。重复值的一壹将保留在 protocol
    buffer 中。能够将 repeated 字段视为动态大小的数组。

倡议服务请求

今昔您已经把当地服务器跑起来了,是时候在 app
中倡导服务请求了。**RWService.swift **文这几个高中将 RWService
类替换来上面包车型客车代码:

class RWService {
  static let shared = RWService() // 1
  let url = "http://127.0.0.1:5000"

  private init() { }

  func getCurrentUser(_ completion: @escaping (Contact?) -> ()) { // 2
    let path = "/currentUser"
    Alamofire.request("\(url)\(path)").responseData { response in
      if let data = response.result.value { // 3
        let contact = try? Contact(protobuf: data) // 4
        completion(contact)
      }
      completion(nil)
    }
  }
}

本条类将用来与你的 Python
服务器举办交互。你已经得以落成了获取当前用户的呼吁:

  1. shared 是三个倡议网络请求的单例。
  2. getCurrentUser(_:) 方法通过 /currentUser
    路线发起了获得用户消息的网络请求,后台会回去一个硬编码的用户音讯。
  3. if let 获取了数量。
  4. data 中蕴藏了服务端重回的 protocol buffer 二进制数据。 Contact
    的构造器以 data 作为入参,解码数据。

解码数据只需求把 protocol buffer
的数额传递给目标的构造器就能够,不需求别的的剖析。 Swift 的 protocol
buffer 库帮你管理了具有的事体。
明天恳请已经形成,能够来得数据了。

对此 required 类型你应有时时刻刻留意,将字段设置为 required
类型是叁个值得谨慎思量的事务。若是您愿目的在于有些时刻结束写入或发送
required 字段,则将字段改换为 optional 字段会有毛病 –
旧读者会认为尚未此字段的邮件不完整,或然会无意中拒绝或删除那么些音信。你应有思虑为你的
buffers
编写特定于应用程序的自定义验证例程。谷歌(谷歌(Google))的一部分程序员得出的定论是,使用
repeated 弊大于利;他们更爱好只行使 optional 和
repeated。但是,那种理念还未获取推广。

合并参加会议者的名片

打开 CardViewController.swift 文件并在 viewWillAppear(_:)
之后增添下边那么些代码:

func fetchCurrentUser() { // 1
  RWService.shared.getCurrentUser { contact in
    if let contact = contact {
      self.configure(contact)
    }
  }
}

func configure(_ contact: Contact) { // 2
  self.attendeeNameLabel.attributedText = NSAttributedString.attributedString(for: contact.firstName, and: contact.lastName)
  self.twitterLabel.text = contact.twitterName
  self.emailLabel.text = contact.email
  self.githubLabel.text = contact.githubLink
  self.profileImageView.image = UIImage(named: contact.imageName)
}

那些办法会帮您获取劳动端传过来的数码,并用来计划名片:

  1. fetchCurrentUser() 请求服务器去赢妥善前用户的音信,并选用 *
    contact* 来配置 * CardViewController*。
  2. configure(_:) 通过传播的 contact 配置UI。

用起来很简短,然则还索要获得一个 ContactType 枚举用来分别参会者的品类。

您能够在 Protocol Buffer 语法指南 中找到编写 .proto
文件(包罗拥有希望的字段类型)的1体化指南。不要去寻觅类似于类承继的工具,protocol
buffers 不会如此做。

自定义 Protocol Buffer 对象

你必要加多2个措施来把枚举类型调换来 string, 那样名片页面本领展现
SPEAKER 而不是四个数字0.
但是那有个难点,假使不另行生成 .proto 文件来更新
message,怎么样技能往模型里加多新功效吗?

澳门金沙国际 9

Swift extensions
能够化解那几个,它能够让您增添一些音信到类中而不须求更换类本人的代码。
始建一个名叫 contact+extension.swift 的文件,并加多到 Protocol
Buffer Objects
目录。增加以下代码:

extension Contact {
  func contactTypeToString() -> String {
    switch type {
    case .speaker:
      return "SPEAKER"
    case .attendant:
      return "ATTENDEE"
    case .volunteer:
      return "VOLUNTEER"
    default:
      return "UNKNOWN"
    }
  }
}

contactTypeToString() 方法将 ContactType
映射成了二个相应的显得用的字符串。
打开 CardViewController.swift 并丰盛上面包车型客车代码到
configure(_:)

self.attendeeTypeLabel.text = contact.contactTypeToString()

将象征contact type的字符串传递给了 * attendeeTypeLabel
最后在
viewWillAppear(_:) 中,applyBusinessCardAppearance()*
之后加多下边代码:

if isCurrentUser {
  fetchCurrentUser()
} else {
  // TODO: handle speaker
}
  • isCurrentUser* 已经被硬编码成 true,
    当棉被服装置为演说者时这些值会被涂改。*fetchCurrentUser() *
    方法在默许意况下会被调用,获取名片音信并将其填充到名片上。
    运作程序来看望参加会议者的片子页面:

澳门金沙国际 10

既是您早就有了2个 .proto
文件,那么你供给做的下1件事就是生成你必要读写AddressBook(以及
PersonPhoneNumber ) message 所需的类。为此,你需求在 .proto
上运行 protocol buffer 编译器 protoc

合并解说者列表

My Badge 选项卡完毕后,我们来看看 Speakers 选项卡。
打开 RWService.swift 并足够上边包车型客车代码:

func getSpeakers(_ completion: @escaping (Speakers?) -> ()) { // 1
  let path = "/speakers"
  Alamofire.request("\(url)\(path)").responseData { response in
    if let data = response.result.value { // 2
      let speakers = try? Speakers(protobuf: data) // 3
      completion(speakers)
    }
  }
  completion(nil)
}

看上去很熟知是啊,它和 getCurrentUser(_:) 类似,可是她得到的是
Speakers 对象,包罗了贰个 contact 的数组,用于表示纪念的发言者。
打开 SpeakersViewModel.swift 并将代码替换为:

class SpeakersViewModel {
  var speakers: Speakers!
  var selectedSpeaker: Contact?

  init(speakers: Speakers) {
    self.speakers = speakers
  }

  func numberOfRows() -> Int {
    return speakers.contacts.count
  }

  func numberOfSections() -> Int {
    return 1
  }

  func getSpeaker(for indexPath: IndexPath) -> Contact {
    return speakers.contacts[indexPath.item]
  }

  func selectSpeaker(for indexPath: IndexPath) {
    selectedSpeaker = getSpeaker(for: indexPath)
  }
}

SpeakersListViewController
展现了两个参加会议者的列表,SpeakersViewModel中涵盖了那么些数据:从
/speakers 接口中获取的contact对象组成的数组。
SpeakersListViewController将要每壹行中展现四个speaker。
viewmodel创建好了随后,就该配置cell了。展开SpeakerCell.swift,加多底下的代码到 SpeakerCell

func configure(with contact: Contact) {
  profileImageView.image = UIImage(named: contact.imageName)
  nameLabel.attributedText = NSAttributedString.attributedString(for: contact.firstName, and: contact.lastName)
}

传扬了三个contact对象并且经过其品质来安顿cell的 image 和
label。那几个cell会突显演说者的照片,和她的名字。
接下来,打开 SpeakersListViewController.swift 并丰盛下边包车型客车代码到
viewWillAppear(_:)中:

RWService.shared.getSpeakers { [unowned self] speakers in
  if let speakers = speakers {
    self.speakersModel = SpeakersViewModel(speakers: speakers)
    self.tableView.reloadData()
  }
}

getSpeakers(_:)倡议了八个请求去赢得解说者列表的数目,创造了2个 *
SpeakersViewModel* 的对象,并再次回到 speakers。 tableview
接下来会更新这么些获得到的数据。
您需求给 tableview
的每一行内定三个speaker用于显示。替换tableView(_:cellForRowAt:)的代码:

let cell = tableView.dequeueReusableCell(withIdentifier: "SpeakerCell", for: indexPath) as! SpeakerCell
if let speaker = speakersModel?.getSpeaker(for: indexPath) {
  cell.configure(with: speaker)
}
return cell

getSpeaker(for:) 依据当前列表的 indexPath重返speaker数据,通过cell的configure(with:)配置cell。
当点击列表中的贰个cell时,你必要跳转到 CardViewController
体现精选的发言者消息,展开 CardViewController.swift
并在类中充裕这个属性:

var speaker: Contact?

前面会用到那些天性用来传递选用的发言者。将// TODO: handle
speaker
替换为:

if let speaker = speaker {
  configure(speaker)
}

本条论断用来鲜明 speaker 是或不是已经填充过了,即便是,调用
configure(),在名片上立异解说者的新闻。
回到 SpeakersListViewController.swift 传递选用的 speaker。在
tableView(_:didSelectRowAt:)中,
performSegue(withIdentifier:sender:) 上方增多:

speakersModel?.selectSpeaker(for: indexPath)

将 speakersModel 中的对应 speaker 标志为当选。
接下来,在prepare(for:sender:)vc.isCurrentUser = false:
之后加多下边包车型大巴代码:

vc.speaker = speakersModel?.selectedSpeaker

这里讲 selectedSpeaker 传递给了 * CardViewController* 来显示。
保障您的本地服务还在运转个中,build & run Xcode。你会看出 app
已经济合营龙了用户名片,同时出示了演说者的新闻。

澳门金沙国际 11

您已经成功地用斯威夫特的客户端和Python的服务端,创设好了2个应用程序。客户端和服务端同时利用了由
proto
文件成立的模型。假设你须求修改模型,只须求简单地运作编写翻译器并再一次生成,就能即时得到两端的模型文件!

  1. 若是未有安装编写翻译器,请 下载软件包 并根据 README
    文件中的表明实行操作。
  2. 现行反革命运作编译器,钦命源目录(应用程序的源代码所在的职位 –
    倘使不提​​供值,则应用当前目录),目标目录(你期望生成代码的目的目录;通常与源目录
    $SRC_DIR 相同),以及 .proto
    的路径。在那种场地下,你能够实行如下命令:

    protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto
    

总结

你能够从
这里下载到成功的工程。
在这篇教程中,你早就学习到了 protocol buffer 的基本特征, 怎么着定义一个.proto 文件并通过编写翻译器生成 Swift 文件。还学习了怎样行使Flask
成立3个简便的本地服务器,并利用那个服务发送 protocol buffer
的二进制数据给客户端,以及如何轻巧地去反体系化数据。
protocol buffers 还有越来越多的表征,比方说在 message
中定义映射和拍卖向后卓殊。假诺你对那个感兴趣,能够查看 谷歌的文档。

最后值得1提的是,Remote Procedure Calls那一个项目应用了 protocol
buffers
并且看起来越发不易,访问GRPC叩问越多啊。

因为您需求 C ++ 类,所以采取 --cpp_out 选项 –
当然,为此外帮忙的言语也提供了看似的选项。

那就要钦命的目的目录中生成以下文件:

  • addressbook.pb.h: 类表明的头文件
  • addressbook.pb.cc:类实现

让我们看看一些变型的代码,看看编写翻译器为你创造了如何类和函数。假设您查看
addressbook.pb.h,你会意识你在 addressbook.proto 中钦定的每条 message
都有2个一见如旧的类。仔细察看 Person
类,你能够见到编写翻译器已为各样字段生成了访问器。举个例子,对于 name
,id,email 和 phone 字段,你能够应用以下措施:

 // required name inline bool has_name() const; inline void clear_name(); inline const ::std::string& name() const; inline void set_name(const ::std::string& value); inline void set_name(const char* value); inline ::std::string* mutable_name(); // required id inline bool has_id() const; inline void clear_id(); inline int32_t id() const; inline void set_id(int32_t value); // optional email inline bool has_email() const; inline void clear_email(); inline const ::std::string& email() const; inline void set_email(const ::std::string& value); inline void set_email(const char* value); inline ::std::string* mutable_email(); // repeated phones inline int phones_size() const; inline void clear_phones(); inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >& phones() const; inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >* mutable_phones(); inline const ::tutorial::Person_PhoneNumber& phones(int index) const; inline ::tutorial::Person_PhoneNumber* mutable_phones(int index); inline ::tutorial::Person_PhoneNumber* add_phones();

如你所见,getter 的名号与小写字段完全一样,setter 方法以 set_
初始。每一种单数(required 或 optional)字段也有 has_
方法,假如设置了该字段,则赶回 true。最后,各种字段都有贰个 clear_
方法,可以将字段重新安装回 empty 状态。

固然如此数字 id 字段只有上面描述的中坚访问器集,可是 name 和 email
字段因为是字符串所以有多少个附加的主意:1个 mutable_澳门金沙国际 , 的
getter,它同意你收获贰个对准字符串的直白指针,以及一个外加的
setter。请留心,固然未有安装 email ,也能够调用
mutable_email();它将自行早先化为空字符串。若是在那些例子中您有二个单数的
message 字段,它也会有3个 mutable_ 方法而不是 set_ 方法。

repeated 字段也有1部分破例的方法 – 假使你看一下 repeated phones
字段的连带办法,你会意识你能够:

  • 自己探究 repeated 字段长度(换句话说,与这个人涉嫌的电话号码数)
  • 应用索引获取内定的电话号码
  • 履新钦赐索引处的水保电话号码
  • 在 message 中加多另一个电话号码同时之后也可进行再修改(repeated
    的标量类型有一个 add_,而且只同意你传入新值)

关于 protocol 编写翻译器为其余特定字段定义生成的适当成员的详细音讯,请参阅
C++ 生成代码参考。

改换的代码包括与你的 .proto 枚举对应的 PhoneType
枚举。你能够将此类型称为 Person::PhoneType,其值为
Person::MOBILE,Person::HOME 和
Person::WO君越K(落成细节稍微复杂一些,但你若是仅仅只是使用不需求明白里面包车型大巴贯彻原理)。

编译器还为你生成了一个名称为 Person::PhoneNumber
的嵌套类。要是翻开代码,能够看看 “真实” 类实际上称为
Person_PhoneNumber,但在 Person 中定义的 typedef
允许你将其正是嵌套类。唯一会形成有个别差别的状态是,假如你想在另二个文书中前向注脚该类

  • 您不可能在 C ++ 中前向注明嵌套类型,但您可在此以前向注明Person_PhoneNumber。

每一个 message 类还带有众多别样方法,可用以检查或操作整个 message,包蕴:

  • bool IsInitialized() const;: 检查是还是不是已安装富有必填 required 字段
  • string DebugString() const;: 重返 message
    的人类可读表明,对调养尤其有用

  • void CopyFrom(const Person& from);: 用给定的 message 的值覆盖
    message
  • void Clear();: 将全部因素清除回 empty 状态

那些和下一节中讲述的 I/O 方法落成了具备 C++ protocol buffer 类共享的
Message 接口。愈多的更详细的有关音讯,请参阅 Message 的总体 API 文书档案。

最终,每一种 protocol buffer 类都有应用 protocol buffer 贰进制格式
读写所选类型 message 的主意。蕴涵:

  • bool SerializeToString(string* output) const;:类别化新闻并将字节存储在给定的字符串中。请留心,字节是2进制的,而不是文件;大家只使用
    string 类作为惠及的器皿。
  • bool ParseFromString(const string& data);: 解析给定字符串到
    message
  • bool SerializeToOstream(ostream* output) const;: 将 message
    写入给定的 C++ 的 ostream
  • bool ParseFromIstream(istream* input);: 解析给定 C++ istream 到
    message

那一个只是分析和种类化提供的多少个挑选。请参阅 Message API 参考
以获得完整列表。

Protocol Buffers 和 O-O 设计的 Protocol Buffers 类基本上是 dumb data
持有者;
他们一直不在目的模型中变为能够的一等公民。假设要为生成的类增加更丰盛的表现,最棒的秘技是将扭转的
Protocol Buffers 类包装在特定于应用程序的类中。假使您不能调控 .proto
文件的规划(要是你正在重用另1个品种中的1个),那么包装 Protocol
Buffers
的类也是2个好主意。在那种景况下,你可以使用包装器类来创设更切合应用程序的出格情状的接口:隐藏一些多少和艺术,公开便利作用等。永久不应有经过持续它们来为变化的类增多行为。这将打破内部机制,无论如何那都不是好好的面向对象的实行。

翻译注:对象模型设计条件之一:使用组合代表承继

如今让大家尝试接纳你的 Protocol Buffer
类。你指望地址簿应用程序能够做的首先件事恐怕是将民用详细新闻写入的地址簿文件。为此,你供给创制并填充
Protocol Buffer 类的实例,然后将它们写入输出流。

那是二个从文件中读取 AddressBook 的主次,依照用户输入向其拉长三个新
Person,并将新的 AddressBook 重新写回文件。在那之中央直机关接调用或引用 protocol
编写翻译器生成的代码部分将高亮展现。

翻译注:“直接调用或引用 protocol 编写翻译器生成的代码部分” 选用注释 @@@
的主意标出

#include <iostream>#include <fstream>#include <string>#include "addressbook.pb.h"using namespace std;// This function fills in a Person message based on user input.void PromptForAddress(tutorial::Person* person) { cout << "Enter person ID number: "; int id; cin >> id; person->set_id; cin.ignore(256, '\n'); cout << "Enter name: "; getline(cin, *person->mutable_name; cout << "Enter email address (blank for none): "; string email; getline(cin, email); if (!email.empty { person->set_email; } while  { cout << "Enter a phone number (or leave blank to finish): "; string number; getline(cin, number); if (number.empty { break; } // @@@ Person::PhoneNumber tutorial::Person::PhoneNumber* phone_number = person->add_phones(); phone_number->set_number; cout << "Is this a mobile, home, or work phone? "; string type; getline(cin, type); if (type == "mobile") { // @@@ Person phone_number->set_type(tutorial::Person::MOBILE); } else if (type == "home") { // @@@ Person phone_number->set_type(tutorial::Person::HOME); } else if (type == "work") { // @@@ Person phone_number->set_type(tutorial::Person::WORK); } else { cout << "Unknown phone type. Using default." << endl; } }}// Main function: Reads the entire address book from a file,// adds one person based on user input, then writes it back out to the same// file.int main(int argc, char* argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } // @@@ AddressBook tutorial::AddressBook address_book; { // Read the existing address book. fstream input(argv[1], ios::in | ios::binary); if  { cout << argv[1] << ": File not found. Creating a new file." << endl; // @@@ ParseFromIstream } else if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } // Add an address. PromptForAddress(address_book.add_people; { // Write the new address book back to disk. fstream output(argv[1], ios::out | ios::trunc | ios::binary); // @@@ SerializeToOstream if (!address_book.SerializeToOstream(&output)) { cerr << "Failed to write address book." << endl; return -1; } } // Optional: Delete all global objects allocated by libprotobuf. // @@@ ShutdownProtobufLibrary google::protobuf::ShutdownProtobufLibrary(); return 0;}

请注意 GOOGLE_PROTOBUF_VERIFY_VE奥迪Q3SION 宏。在运用 C++ Protocol Buffer
库在此以前施行此宏是1种很好的做法 –
就算不是纯属少不了的。它表达你从未意外链接到与你编写翻译的头文件不般配的库版本。如若检查测试到版本不合营,程序将刹车。请留心,每一个.pb.cc 文件在运行时都会自行调用此宏。

另请留目的在于先后结束时调用 ShutdownProtobufLibrary()。全部那一切都以删除
Protocol Buffer
库分配的兼具全局对象。对于大多程序来讲那是不必要的,因为该进度无论如何都要剥离,并且操作系统将担当回收其抱有内部存款和储蓄器。不过,若是您使用了内部存款和储蓄器泄漏检查程序,该程序须求释放每一种最终对象,可能您正在编纂能够由单个进程数十二回加载和卸载的库,那么您或者希望强制行使
Protocol Buffers 来清理全体内容。

本来,如若您不能够从中获得别的音讯,那么地址簿就不会有多大用处!此示例读取下面示例创立的文书并打字与印刷在那之中的富有音讯。

#include <iostream>#include <fstream>#include <string>#include "addressbook.pb.h"using namespace std;// Iterates though all people in the AddressBook and prints info about them.void ListPeople(const tutorial::AddressBook& address_book) { for (int i = 0; i < address_book.people_size { const tutorial::Person& person = address_book.people; cout << "Person ID: " << person.id() << endl; cout << " Name: " << person.name() << endl; if (person.has_email { cout << " E-mail address: " << person.email() << endl; } for (int j = 0; j < person.phones_size { const tutorial::Person::PhoneNumber& phone_number = person.phones; switch (phone_number.type { case tutorial::Person::MOBILE: cout << " Mobile phone #: "; break; case tutorial::Person::HOME: cout << " Home phone #: "; break; case tutorial::Person::WORK: cout << " Work phone #: "; break; } cout << phone_number.number() << endl; } }}// Main function: Reads the entire address book from a file and prints all// the information inside.int main(int argc, char* argv[]) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; if (argc != 2) { cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << endl; return -1; } tutorial::AddressBook address_book; { // Read the existing address book. fstream input(argv[1], ios::in | ios::binary); if (!address_book.ParseFromIstream(&input)) { cerr << "Failed to parse address book." << endl; return -1; } } ListPeople(address_book); // Optional: Delete all global objects allocated by libprotobuf. google::protobuf::ShutdownProtobufLibrary(); return 0;}

在揭橥使用 protocol buffer 的代码之后,无疑早晚有1天你将会想要 “创新”
protocol buffer 的定义。如若您愿意您的新 buffer 向后至极,并且你的旧
buffer 是前进包容的(实际上你分明想要那种包容性) –
那么你须求依照一些规则。在新本子的 protocol buffer 中:

  • 您不行改换任何现成字段的字段编号
  • 您不可加多或删除任何 required 字段
  • 你能够去除 optional 或 repeated 的字段
  • 您能够增多新的 optional 或 repeated
    字段,但必须运用新的标识号(即未有在此协议缓冲区中选取的号码,以至包涵那几个已删除的字段的号子)

(那个规则有部分 例外,但它们很少使用)。

倘若你根据这个规则,旧代码将很情愿阅读新音讯并简要地忽视任何新字段。对于旧代码,已去除的可选字段将只具有其暗许值,删除的再度字段将为空。新代码也将透明地读取旧音信。可是,请牢记旧的
message 中不会冒出新的可选字段,因此你供给肯定通过调用 has_
方法来检查它们是否被安装,只怕在字段编号前边使用 [default = value] 在
.proto 文件中提供客观的暗中同意值。假使未为 optional
成分内定暗许值,则选择一定于类型的私下认可值:对于字符串,默认值为空字符串。对于布尔值,暗中同意值为
false。对于数字类型,暗许值为零。另请留心,如若增多了新的 repeated
字段,则新代码将一点都不大概推断它是还是不是为空或尚未安装,因为它从不 has_ 标志。

C++ Protocol Buffers
已经做了天崩地坼优化。可是,精确行使能够进一步升高质量。以下是压榨最终一点进程的局地唤起和手艺:

  • 尽心尽力重用 message 对象。message
    会为了重用尝试保留它们分配的其余内部存款和储蓄器,尽管它们被破除。因此,要是你总是管理具备同样档期的顺序和接近结构的大队人马
    message,则每一趟重复选择同样的 message
    对象来加载内部存款和储蓄器分配器是个好主意。不过,随着时间的推迟,对象会变得臃肿,尤其是就算您的
    message 在 “形状” 上有所分裂,可能你偶尔构造的 message
    比常常大得多。你应当通过调用 SpaceUsed
    方法来监督邮件对象的大小,1旦它们变得太大就删除它们。
  • 你的系统内部存款和储蓄器分配器恐怕未有针对性从多少个线程分配多量小目的那种景观展开优质优化。请尝试使用
    谷歌 的 tcmalloc。

Protocol buffers 的用途不仅仅是简简单单的访问器和体系化。请务必浏览 C++ API
参考,以询问您能够选取它们做些什么。

Protocol buffers 类提供的贰个首要特性是反光。你能够迭代 message
的字段并决定它们的值,而无需针对其余特定的 message
类型编写代码。使用反射的壹种卓殊管用的施用是将 protocol messages
转变为其余编码,举个例子 XML 或
JSON。越来越高端的反射用法大概是找到七个壹律档期的顺序的 message
之间的差异,也许支付一种 “protocol messages
的正则表明式”,你能够在里边编写与一些 message
内容格外的表明式。假如你使用本身的想象力,能够将 Protocol Buffers
应用于比你最初预期更分布的难题!

反射由 Message::Reflection 接口. 提供。

相关文章