【美高梅手机版4858】法定文书档案,中的使用

By admin in 美高梅手机版4858 on 2019年4月19日

行事中必要接纳protocol
buffer,需求编译出protocol
buffer的动态链接库,然后在别的makefile中链接它,

翻译自:Introduction to Protocol Buffers on
iOS

下载并编写翻译Protocol Buffer

那份教程为C++开采者提供了应用 Protocol Buffer
的为主介绍。通过创设1个简约利用,它展现了

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

那不是1个在C++中运用 Protocol Buffer美高梅手机版4858,
的因人而异指南。越多详细的音信,请参考Protocol
Buffer语言指南,
C++
API参考,C++
Generated Code
Guide,和
编码参考【美高梅手机版4858】法定文书档案,中的使用。。

翻译查阅外网资料进程中遇见的比较可观的篇章和材质,一是用作才具参考以便日后查阅,贰是操练英文本领。

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

翻译为意译,不会一板一眼的字字对照翻译以下为最初的作品内容翻译

自作者的条件是ubnutu16.0四,64bit,使用的protocol buffer 版本是v三.五

对大部分的行使来讲,后台服务、传输和存款和储蓄数据都以个根本的模块。开辟者在给叁个web service 写接口时,经常选择 JSON 也许 XML
来发送和接收数据,然后依照那一个数据变动结构并分析。

为什么使用Protocol Buffers?

大家将动用的事例是2个非凡简单的 “address book”
应用,它能够从文件读取和向文件写入人们的联系人实际情况。地址簿中的每一个人有着2个名字
(name),ID,电子邮件地址 (email address),和联系人电话号码 (contact
phone)。

你要什么样连串化和领取那样的结构化数据吧?有一对措施能够消除那几个标题:

  • 土生土长的内部存储器数据结构能够以2进制的款型发送/保存。随着时间的流逝,那是1种脆弱的艺术,因为接到/读取的代码必须以完全一样的内部存款和储蓄器布局、尾端等等编写翻译。其它,随着文件以原始的格式累积数据及处理那种格式的软件的复制,那种格式被频频扩散,则它是充足不便扩展的格式。

  • 您能够说雅培种特别的艺术来将数据项编码编码为贰个字符串 ——
    比如将三个int值编码为”1二:三:-二三:67″。那是一个简便而灵活的方法,尽管它须要编制1次性的编码和分析代码,而且解析消耗一小段运转时代价。那对于编码万分简单的数额是最棒的点子。
    将数据种类化为XML。那种方法只怕那么些富有吸重力,因为XML是 (有点)
    人类可读的,而且它有恢宏编制程序语言的bindings库。借使您想要与别的的施用/项目共享数据以来,那大概是二个很好的挑三拣四。但是,XML是臭名昭著的空中密集,而且编码/解码它需求消耗应用多量的习性成本。而且,浏览贰个XML
    DOM树也被以为比经常浏览类中的轻易字段更扑朔迷离。

Protocol buffers 是杀鸡取卵这些难点灵活,高效,自动化的方案。通过
Protocol buffers ,你能够编写叁个 .proto
描述您想要存款和储蓄的数据结构。通过它, Protocol buffers
编译器成立四个类,以一种高效的2进制格式达成机关的编码和平解决析 Protocol
buffers
数据。生成的类为组合1个 Protocol buffers
的字段提供了getters和setters方法,并处理读取和写入 Protocol buffers
的底细。首要地是, Protocol buffers
格式通过使代码还是可以读取用老的格式编码的数目来支撑随着时光对格式的庞大。

本学科为 C++ 程序员怎么样利用 protocol buffers
做3个主干介绍。通过创立二个简短的言传身教应用程序,它向您出示:

率先大家须求下载protocol
buffer源码,然后遵照教程进行安装:

尽管有雅量的 API
和框架接济大家系列化和反连串化,来支撑部分后台接口开垦的日常工作,比如说更新代码大概解析器来扶助后台的模子变化。

在何地能够找到示例代码

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

  • 怎么着在2个 .proto 文件中定义 message
  • 何以使用 protocol buffer 编写翻译器
  • 什么样运用 C++ protocol buffer 的 API 读写 message

参考目录:

可是假诺你实在想进步你的新类型的健壮性的话 ,思量下用 protocol
buffers,它是由
谷歌(Google)开荒用来连串化数据结构的一种跨语言的措施。在重重情景下,它比守旧的 JSON
和 XML
更灵活有效。个中二个第三的特色正是,你只须求在其辅助的别的语言和编写翻译器下,定义二回数据结构——包蕴斯威夫特! 创制的类公事就能够很轻巧的读写成靶子。

概念你的商议格式

为了成立你的地址簿应用,你须求先创立一个 .proto 文件。 .proto
文件中的定义很轻松:为每种你想要体系化的数据结构增加叁个 消息(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,或WOENVISIONK中的二个。

种种成分上的 ” = 一”,” = 贰”标识标志在二进制编码中使用的该字段唯壹的
“tag” 。Tag数字 一-壹5比越来越大的数字在编码上少一个字节,因此作为一种优化,你能够操纵将那些数字用作常用的或再度的因素的tag,而将1陆及越来越大的数字tag留给特别不常用的可选成分。重复字段中的种种成分须求重编码tag数字,由此那种优化越发适用于重新字段。

种种字段必须用上面包车型大巴修饰符中的四个来疏解:

  • required:字段必须提供,不然音信将被以为是 “未开始化的
    (uninitialized)”。假使libprotobuf以debug格局编写翻译,则系列化未开头化的信息将变成断言失利。在优化的营造中,检查将被跳过,音讯仍将被写入。但是,解析未开首化的音讯将一而再退步(通过喜爱parse方法中回到false)。不然,required字段的行为将与optional字段完全一样。

  • optional:字段能够安装也足以不设置。若是可选的字段值未有设置,则将选取默许值。对于简易的花色,你能够内定你自个儿的暗中同意值,如笔者辈在例子中为电话号码类型做的那样。不然,将动用系统暗中同意值:数字类型为0,字符串类型为空字符串,bools值为false。对于内嵌的新闻,默许值总是音信的
    “暗许实例 (default instance)” 或
    “原型(prototype)”,它们从不团结的字段集。调用accessor获取还向来不显式地设置的
    optional (或required) 字段的值总是回到字段的暗许值。

  • repeated:字段可以再一次任意数次 (包罗0)。在 protocol buffer
    中,重复值的逐条将被封存。将重新字段想象为动态大小的数组。

你将找到贰个编写制定 .proto 文件的完全指南 —— 包括具备望的字段类型 ——
在Protocol Buffer Language
Guide
一文中。不要寻觅与类承接类似的设备 —— protocol buffer 不那么做。

那不是壹篇通过 C ++ 使用 protocol
的回顾指南。若是想得到更详尽的参照音讯,请参阅 Protocol Buffer
语法指点、C++ API 指导、C++ 生成代码辅导 和 Protocol Buffer 的
编码引导。

设置步骤:

在那篇教程中,会动用3个 Python 服务端与2个 iOS 程序交互。你会学到
protocol buffers 是如何工作,怎么着布署环境,最终什么利用 protocol buffers
传输数据。

编写翻译你的Protocol Buffers

明日您有了贰个.proto,接下去你须要做的工作是生成读写 AddressBook
(及Person 和 PhoneNumber) 音信所需的类。要到位那点,你须求在你的
.proto 上运转 Protocol Buffers 编译器protoc:

  1. 若果您还从未设置编写翻译器,则下载包,并依据README的指令实行。

  2. 近来运作编写翻译器,钦命源目录 (放置你的利用程序源代码的地点 ——
    假诺您未有提供则选择当前目录),目标目录
    (你希望放置生成的代码的职位;平常与$S凯雷德C_DISportage一样),你的.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。最终,种种字段具备1个clear_ 方法,用于将字段设置回它的空状态。

数字的id字段唯有基本的看来的accessor
set,而name和email字段则有一对额外的方法,因为它们是字符串 ——
一个mutable_
getter,让您赚取指向字符串的直接的指针,及贰个非常的setter。注意你能够调用mutable_email(),尽管email还未曾设置;它将被电动地初始化为三个空字符窜。假使在这些事例中您有3个单数的消息字段,它将还有五个mutable_方法,而没有set_方法。

再度的字段还有一部分尤其的主意 ——
就算你查正视复的phone字段的秘诀的话,你将看到您可以

  • 自笔者批评重复字段的 _size
    (换句话说,与这些Person关联的电话号码有个别许个)。
  • 使用索引获得三个一定的电话号码。
  • 立异特定岗位处的已有电话号码。
  • 给音信增加另三个背后你能够编写的电话号码
    (重复的标量类型具备2个add_ 以使你能够流传新值)。

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

您该怎么连串化和反系列化如上组织的多少吧?那里有两种缓解方案:

中间需求专注的地点,安装软件的时候,大概出现破产的标题,建议将ubnutu软件源改为阿里Baba的源大概今日头条的源,具体操作方法请百度。

留神:那篇教程是依据你曾经有了必然的 iOS 和 斯维夫特经验,同时有自然的主导的服务端和 terminal 基础。
而且,确定保证您选拔的是苹果的 Xcode 捌.二或未来的版本.

枚举和嵌套类

转移的代码包括3个PhoneType枚举,它对应于你的.proto枚举。你能够以Person::PhoneType引用那么些类型,它的值包涵Person::MOBILE,Person::HOME,和Person::WO索罗德K
(落成细节要复杂一点,但你使用枚举时无需精通它们)。

编译器还为你生成了名称为Person::PhoneNumber的嵌套类。若是您看代码,会意识
“真实的” 类实际称为
Person_PhoneNumber,但定义在Person内的typedef使您能够像贰个嵌套类同样接纳它。会影响到的仅部分意况是,假如您想要在另3个文书中前向评释类
—— 你不能够在C++中前向证明嵌套类型,但您可在此以前向评释Person_PhoneNumber。

  • 能够以贰进制方式发送/保存原有内部存款和储蓄器中数据结构。随着时光的延迟,那是1种脆弱的办法,因为接受/读替代码必须运用完全一样的内部存储器布局、字节顺序等举行编写翻译。其它,由于文件以原始格式累积数据,并且解析该格式的软件别本到处扩散,由此很难扩大格式。

  • 你能够表雅培(Abbott)种特殊的办法将数据项编码为单个字符串 – 例如将 陆个整数编码为
    “1二:三:-二3:六7″。那是一种简易而灵活的主意,就算它实在必要编写制定1次性编码和分析的代码,并且解析会发出局地小的运维时资金。但那格外适合非凡轻松的多寡的编码。

  • 将数据类别化为 XML。那种方法丰盛有吸重力,因为
    XML是人类可读的,并且有众多言语的绑定库。要是您想与别的应用程序/项目共享数据,那大概是二个不错的精选。不过,XML
    是明确须要更多的空中,并且编码/解码 XML
    会对应用程序形成巨大的习性损失。其它,导航 XML DOM
    树比平常在类中程导弹航轻便字段要复杂得多。

然后这里要留意curl
和libcurl版本要1致,不然./autogen.sh的时候会报错。

有备无患上马

RWCards其一应用程式能够用来查看你的议会门票和演说者名单。下载Starter
Project并开荒根目录Starter。先熟知一下那下边那3有的:

规范的消息方法

每一个新闻类还蕴藏大量的任何方法,来让你检查或管理整个信息,包括:

  • 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,你能够写一个 .proto 文件讲述您想要读取的多寡的组织。由此,
protocol buffer 编写翻译器将开创叁个类,该类应用有效的贰进制格式达成protocol buffer 数据的自动编码和分析。生成的类为组合 protocol buffer
的字段提供 getter 和 setter,并担负读写 protocol buffer
单元的底细。首要的是,protocol buffer
的格式帮忙随着年华的延期扩张格式的想法,使得代码还是能够读取用旧格式编码的多寡。

最后生成的库如下: 

The Client

Starter/RWCards下,打开
RWCards.xcworkspace,大家来看望那多少个重点的文本:

  • SpeakersListViewController.swift
    管理了贰个用来展示阐述者名单的table
    view。这么些调节器今后还只是个模板因为你还从未为其创设模型。
  • SpeakersViewModel.swift 相当于 SpeakersListViewController
    的数据源,它会蕴藏有演说者的名单数据。
  • CardViewController.swift 用来展现参加会议者的片子和他的交际新闻.
  • RWService.swift 管理客户端和后端的互动。你恐怕会用到
    Alamofire 来发起服务请求。
  • Main.storyboard 整个 APP 的 storyboard.

任何工程选拔
CocoaPods
来拉取那八个框架:

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

只顾:那篇教程中你会用到 Swift Protobuf 0.玖.贰四 和 谷歌(Google)’s Protoc
Compiler 三.一.0. 它们曾经打包在项目里了,所以您不须求再做其余。

Parsing and Serialization解析和系列化

最后,每一种protocol buffer类都有利用protocol buffer
2进制格式写和读你所挑选类别的信息的情势。这个情势包罗:

  • 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” 目录下。下载地址

 美高梅手机版4858 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;
};

以此文件里定义了一个 Contact 的 message 和它的连锁属性。

.proto 文件定义好了后,你只必要把那个文件提交 protocol buffer
的编写翻译器,编译器会用你挑选的语言成立好三个数据类(Swift 中的
结构)。你可以直接在类型中使用那么些类/结构,11分轻松!

美高梅手机版4858 2

编写翻译器会将 .proto 中的 message
转换来事先选取的言语,并转移模型对象的源文件。后边会涉嫌定义.proto音讯的越来越多细节。
别的在思索 protocol buffers 此前,你应当思念它是否你项目标最好方案。

写消息

近年来让我们试着使用protocol
buffer类。你想要你的地址簿应用能够做的首先件工作是将个人实际情况写入地址簿文件。要成功那或多或少,你须要创立并防止你的protocol
buffer类的实例,然后将它们写入3个输出流。那里是1个主次,它从二个文书读取多少个AddressBook,基于用户输入给它增添1个新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_VEBMWX五SION宏。它是精美的实行 ——
尽管不是严格必须的 —— 在采纳C++ Protocol
Buffer库以前实行那些宏。它注解你未曾偶然地链接一个与您编写翻译的头文件版本不相配的库版本。如若探测到版本不合营,程序将适可而止。注意各种.pb.cc文件自动地在运行时调用那些宏。

还要主要在程序的终极调用ShutdownProtobufLibrary()。那一个手续做的具有事情是剔除Protocol
Buffer库分配的全局对象。这对许多顺序都以不须求的,因为经过退出后,OS将回收它的具备内从。然则,若是您利用了内部存款和储蓄器泄漏检查工具,它供给种种对象都被保释,也许壹旦你在编写3个库,它可能被单独的进度加载和卸载数次,则你大概想要强制Protocol
Buffers清理全数的东西。

要成立地址簿应用程序,你供给从 .proto 文件伊始。.proto
文件中的定义很简单:为要系列化的各类数据结构增加 message 定义,然后为
message 中的每种字段钦定名称和类型。下边就是定义相关 message 的 .proto
文件,addressbook.proto。

浮动的库文件在/usr/local/lib文件夹下。前面就能够依据本人索要选拔适当的库文件。

优势

JSON 和 XML 或许是当下开采者们用来存款和储蓄和传输数据的科班方案,而 protocol
buffers 与之比较有以下优势:

  • 赶快且小巧:遵照 谷歌 所讲述的,protocol buffers
    的体积要小3-10倍,速度比XML要快20-100倍。能够在那篇文章
    ,它的撰稿人是 Damien Bod,文中相比了部分主流文本格式的读写速度。
  • 体系安全:Protocol buffers 像 Swift 同样是项目安全的,使用
    protocol buffers 时 你需求钦点每3个属性的门类。
  • 自动反体系化:你不要求再去编写任何的解析代码,只要求更新
    .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
确确实实有珍视重的优势。
把程序运转起来试试看呢。

美高梅手机版4858 3

不幸的是您以往还看不到任何新闻,因为数据源还未有开始化。你要做的是呼吁服务端并且将解说者和参加会议者数据填充到页面上。首先,你会合到项目中提供的:

恢宏3个Protocol Buffer

在你发布使用你的protocol buffer的代码之后或早或完,你都将毫无疑问的想要
“进步” protocol
buffer的定义。假若你想要你的新buffers向后卓越,你的老buffers向前包容 ——
你当然差不多连接想要那样 —— 然后您有一对规则要信守。在新本子的protocol
buffer中:

  • 必然不能够 修改任何已有字段的tag数字。
  • 早晚不可能 增加或删除required字段。
  • 可以 删除可选的或重复的字段。
  • 可以 加多可选或重新的字段,但您不能不运用新的tag数字
    (比如,从未在这么些protocol
    buffer中选择过的tag数字,甚至是在剔除的字段中也是)。

(那一个规则有
有个别两样
,但它们大概从未利用)

只要您依照那几个规则,老代码将欢天喜地地读取新音信并简短地忽视新字段。对于老代码来讲,删除的可选字段将简单的装有它们的暗中认可值,删除的双重字段将是空的。新代码将透明地读取老音讯。不过,请记住新的可选字段将不会油不过生在老的消息中,因而你将索要显示地反省它们是或不是因而has_设置了,或通过
[default = value] 在您的 .proto
文件中的tag数字背后提供1个靠边的暗中同意值。如若未有为可选元素内定暗许值,则会接纳一定于类型的暗许值替代:对于字符串,暗许值是空字符串。对于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是因在那之中度优化了的。不过,适当的使用可以进级更加多属性。那里是一些提示,用于从库中挤出每一滴质量:

  • 假若大概就收音和录音音讯。音讯新闻会尝试保留它们分配的内存以复用,甚至当它们被清理的时候。那样,假诺您在连接处理同样连串及类似结构的众多新闻,则每一趟复用同样新闻对象就是一个暴跌内部存款和储蓄器分配器负载的好主意。然后,对象大概随着变得膨胀,特别是只要您的消息在
    “形状(shape)”
    上时时改变,或只要您偶尔构造了一个比一般情状大过多的音信。你应当经过调用
    SpaceUsed
    方法监视你的音讯对象的大大小小,并在它们变的太大时去除它们。

  • 您的类别的内部存款和储蓄器分配器可能未有针对在八线程中抽成多量小目的做个很好的优化。则尝试使用
    Google的tcmalloc
    来代替。

.proto 文件以 package 注明起初,那有助于防备不相同类型里面包车型大巴命名抵触。在
C++ 中,生成的类将放在与包名相配的 namespace 中。

服务端

Starter/Server 目录下包罗:

  • RWServer.py
    是放在Flask上的三个Python 服务。包括八个 GET 请求:

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

后天是时候配置环境来运营 protocol buffers
了。在下边包车型地铁章节中,你会创建好运营 Google 的 protocol
buffer编写翻译器环境,斯威夫特 的 Protobuf 插件,并安装 Flask 来运作你的 Python
服务。

尖端用法

Protocol buffers的应用境况不仅仅是简约的存取器和序列化。确定保证浏览 C++
API
参考
来了然你仍是能够用它做什么。

由protocol新闻类提供的二个最重要意义是 反射
。你能够迭代3个新闻的字段,并在不针对特定的新闻类型编写你的代码的场合下,管理它们的值。使用反射的2个尤其管用的艺术是将protocol音讯转换为别的编码格局,或从别的编码方式转变,比如XML或JSON。反射的2个更加高档的选取大概是索求同样档次的三个新闻之间的差距,可能支付某种”protocol新闻正则表明式”,你能够编写制定表明式用它万分某壹音信内容。倘使利用你想象力,则将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
项目中带有了三个名字为 protoInstallation.sh
的本子帮您化解了那么些。它会在安装此前检查是还是不是曾经设置过那几个库。
这一个剧本须要花一点光阴来设置,特别是设置 谷歌(Google) 的 protocol buffer
库。展开你的极限,cd 命令进入到 Starter 目录施行上面这些命令:

$ ./protoInstallation.sh

只顾:推行的历程中您大概会被要求输入管理员密码。

剧本执行到位后,再运维1次以有限支撑的到以下输出结果:

美高梅手机版4858 4

若是您看看那么些,那表示脚本已经实行完结。假使脚本实行倒闭了,那检查下你是或不是输入了错误的管理员密码。一碗水端平复运营脚本;它不会重新安装那二个已经成功的库。
以此剧本做了这个事:

  1. 设置 Flask 以运营 Python 当地服务。
  2. 从 Starter/protobuf-3.①.0 目录下生成 protocol buffer 编写翻译器。
  3. 设置 protocol buffer 的 Python 模块,那样服务端可以动用 Protobuf
    库。
  4. 将 Swift Protobuf 插件 protoc-gen-swift 移至 /usr/local/bin.
    使 Protobuf 编写翻译器能够生成 斯威夫特 的构造。

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

好了,今后你已经做好了运用 protocol buffers 的有着准备干活。

  • 那里你钦命电话号码,它的值能够是 MOBILE,HOME 或 WO本田UR-VK 之1。

概念一个 .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
    必须选派3个增量且唯1的数字标签。那几个数字用来用于区分音信2进制格式的,这很要紧。访问reserved
    fields能够了解越多关于标签的信息。
  4. Speakers 模型包蕴了 contacts 的成团,* repeated*
    关键字表示3个目的的数组。

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

生成 Swift 结构

contact.proto 传递给 protoc 程序,proto 文件中的 message
将会被转正生成 斯维夫特 的结构。那么些结构会遵守 ProtobufMessage.protoc
并提供 斯威夫特 中结构、方法来类别化和反种类化数据的门径。

只顾:想打听越多关于 Swift 的 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 命令,分别成立了
斯威夫特 和 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** 目录下,你会师到一个 Swift 和一个 Python
文件。同时分别还有3个相应的 .pb.swift.pb.py. pb 前缀表示那是
protocol buffer 生成的类。

美高梅手机版4858 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 字段。

运营本地服务器

示范代码中含有了2个 Python 服务。那么些服务提供了三个 GET
请求:2个用来得到参加会议者的盛名消息,另一个用来列出解说者。
其1课程不会深深批注服务端的代码。尽管如此,你须要理解到它利用了由
protocol buffer 编写翻译器生成的 contact_pb2.py
模型文件。假诺你感兴趣,能够看一看 RWServer.py
中的代码,不看也不要紧(手动好笑)。
展开终端并 cd 至 Starter/Server 目录,运行上面包车型大巴授命:

$ python RWServer.py

运维结果如下:

美高梅手机版4858 6

必须使用以下修饰符之壹注释每个字段:

测试 GET 请求

由此在浏览器中提倡 HTTP 请求,你能够看来 protocol buffer 的原数据。
在浏览器中开垦
http://127.0.0.1:5000/currentUser
你会看出:

美高梅手机版4858 7

再尝试阐述者的接口,http://127.0.0.1:5000/speakers

美高梅手机版4858 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)
    }
  }
}

其1类将用来与你的 Python
服务器进行交互。你早已落到实处了获得当前用户的央求:

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

解码数据只供给把 protocol buffer
的数目传递给目的的构造器就可以,不需求其它的剖析。 Swift 的 protocol
buffer 库帮您处理了独具的事务。
今昔呼吁已经成功,可以来得数据了。

对此 required 类型你应该时时刻刻留意,将字段设置为 required
类型是一个值得谨慎考虑的作业。假如您愿目的在于有个别时刻结束写入或发送
required 字段,则将字段改变为 optional 字段会有难题 –
旧读者会感到并未有此字段的邮件不完全,或许会不知不觉中拒绝或删除那个音讯。你应有思虑为您的
buffers
编写特定于应用程序的自定义验证例程。谷歌(谷歌)的有的工程师得出的结论是,使用
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。

用起来很轻巧,可是还须要得到2个 ContactType 枚举用来区别参加会议者的类别。

你能够在 Protocol Buffer 语法指南 中找到编写 .proto
文件(蕴涵富有相当大希望的字段类型)的完好指南。不要去寻找类似于类承袭的工具,protocol
buffers 不会那样做。

自定义 Protocol Buffer 对象

您供给丰硕贰个艺术来把枚举类型转变来 string, 那样名片页面能力显得
SPEAKER 而不是三个数字0.
而是这有个难题,借使不重复生成 .proto 文件来更新
message,如何才具往模型里增加新功能吗?

美高梅手机版4858 9

Swift extensions
能够消除那些,它能够让您加多一些音信到类中而不要求更改类自己的代码。
开创2个名叫 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
映射成了3个应和的显得用的字符串。
打开 CardViewController.swift 并丰硕下边包车型客车代码到
configure(_:)

self.attendeeTypeLabel.text = contact.contactTypeToString()

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

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

美高梅手机版4858 10

既是您早就有了2个 .proto
文件,那么你供给做的下壹件事就是生成你必要读写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将要每1行中显得贰个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(_:)倡导了二个请求去赢得解说者列表的数额,创立了贰个 *
SpeakersViewModel* 的对象,并赶回 speakers。 tableview
接下来会更新这么些获得到的数量。
您供给给 tableview
的每1行钦赐3个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
已经济合营龙了用户名片,同时出示领会说者的音讯。

美高梅手机版4858 11

你已经成功地用斯维夫特的客户端和Python的服务端,营造好了二个应用程序。客户端和服务端同时选择了由
proto
文件成立的模型。倘若您须要修改模型,只须求轻易地运作编写翻译器并再度生成,就能即时获得两端的模型文件!

  1. 只要未有安装编写翻译器,请 下载软件包 并依据 README
    文件中的表明举行操作。
  2. 明日运作编写翻译器,钦命源目录(应用程序的源代码所在的岗位 –
    假使不提​​供值,则使用当前目录),目的目录(你希望生成代码的目的目录;平时与源目录
    $SRC_DIR 相同),以及 .proto
    的路子。在那种状态下,你能够进行如下命令:

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

总结

你能够从
这里下载到成功的工程。
在那篇教程中,你已经学习到了 protocol buffer 的基本特征, 怎么样定义一个.proto 文件并经过编写翻译器生成 Swift 文件。还学习了怎么运用Flask
创立三个简易的地头服务器,并接纳那些服务发送 protocol buffer
的2进制数据给客户端,以及如何轻易地去反体系化数据。
protocol buffers 还有更加多的特点,比如说在 message
中定义映射和拍卖向后万分。假如你对那个感兴趣,能够查看 谷歌(Google)的文档。

提及底值得壹提的是,Remote Procedure Calls本条种类应用了 protocol
buffers
并且看起来非凡不错,访问GRPC理解越多啊。

因为你须求 C ++ 类,所以利用 --cpp_out 选项 –
当然,为别的帮忙的语言也提供了接近的选项。

那将要钦赐的目的目录中生成以下文件:

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

让大家看看一些生成的代码,看看编译器为您创立了什么样类和函数。借使你查看
addressbook.pb.h,你会意识你在 addressbook.proto 中内定的每条 message
都有二个对应的类。仔细察看 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
字段因为是字符串所以有多少个附加的法子:贰个 mutable_ 的
getter,它同意你收获一个针对性字符串的间接指针,以及三个外加的
setter。请留意,就算没有安装 email ,也得以调用
mutable_email();它将自行初叶化为空字符串。要是在这一个例子中你有二个单数的
message 字段,它也会有八个 mutable_ 方法而不是 set_ 方法。

repeated 字段也有部分奇怪的措施 – 假使你看一下 repeated phones
字段的有关办法,你会意识你可以:

  • 反省 repeated 字段长度(换句话说,与这个人涉嫌的电话号码数)
  • 使用索引获取钦点的电话号码
  • 创新钦定索引处的依存电话号码
  • 在 message 中增添另二个电话号码同时之后也可进展再修改(repeated
    的标量类型有2个 add_,而且只允许你传入新值)

有关 protocol 编写翻译器为任何特定字段定义生成的适合成员的详细音信,请参阅
C++ 生成代码参考。

调换的代码包涵与您的 .proto 枚举对应的 PhoneType
枚举。你能够将此类型称为 Person::PhoneType,其值为
Person::MOBILE,Person::HOME 和
Person::WO卡宴K(达成细节稍微复杂一些,但你假使仅仅只是使用不必要了解里面的贯彻原理)。

编写翻译器还为你生成了二个名字为 Person::PhoneNumber
的嵌套类。假诺查看代码,能够看看 “真实” 类实际上称为
Person_PhoneNumber,但在 Person 中定义的 typedef
允许你将其身为嵌套类。唯壹会导致1些异样的气象是,要是您想在另3个文件中前向评释该类

  • 您不能够在 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 2进制格式
读写所选类型 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
的类也是一个好主意。在这种景观下,你能够使用包装器类来创制更适合应用程序的非正规环境的接口:隐藏一些多少和艺术,公开便利功用等。长久不应有经过持续它们来为扭转的类加多行为。那将打破内部机制,无论怎样那都不是了不起的面向对象的奉行。

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

今昔让我们尝试使用你的 Protocol Buffer
类。你希望地址簿应用程序能够做的首先件事只怕是将民用详细新闻写入的地址簿文件。为此,你须求创造并填充
Protocol Buffer 类的实例,然后将它们写入输出流。

那是3个从文件中读取 AddressBook 的程序,依据用户输入向其拉长3个新
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凯雷德SION 宏。在运用 C++ Protocol Buffer
库此前实行此宏是一种很好的做法 –
固然不是相对要求的。它证明你未曾意外链接到与您编写翻译的头文件不匹配的库版本。借使检验到版本不相称,程序将中止。请小心,每种.pb.cc 文件在运营时都会自行调用此宏。

另请留心在先后结束时调用 ShutdownProtobufLibrary()。全数这1切都以删除
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
已经做了庞大优化。可是,正确利用能够进一步进步品质。以下是压榨最终一点进程的1些提醒和才干:

  • 尽恐怕重用 message 对象。message
    会为了重用尝试保留它们分配的任何内部存储器,尽管它们被解除。因而,假诺你总是处理具备一样档次和接近结构的广大
    message,则每一回重复采纳同一的 message
    对象来加载内部存款和储蓄器分配器是个好主意。不过,随着岁月的推迟,对象会变得臃肿,越发是假设您的
    message 在 “形状” 上有所区别,或许你偶尔构造的 message
    比平常大得多。你应当经过调用 SpaceUsed
    方法来监督邮件对象的分寸,一旦它们变得太大就删除它们。
  • 您的种类内部存款和储蓄器分配器也许未有针对性从多少个线程分配大量小目的那种景色进行特出优化。请尝试选用谷歌(Google) 的 tcmalloc。

Protocol buffers 的用途不仅仅是粗略的访问器和系列化。请务必浏览 C++ API
参考,以明白您能够行使它们做些什么。

Protocol buffers 类提供的两个首要性子是反光。你能够迭代 message
的字段并决定它们的值,而无需针对别的特定的 message
类型编写代码。使用反射的1种十二分管用的使用是将 protocol messages
转变为别的编码,例如 XML 或
JSON。更加尖端的反光用法恐怕是找到三个同样类其余 message
之间的出入,可能开采一种 “protocol messages
的正则表明式”,你能够在中间编写与一些 message
内容极度的表明式。假使您利用本人的想象力,可以将 Protocol Buffers
应用于比你最初预期更加宽泛的主题材料!

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

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有