请选择 进入手机版 | 继续访问电脑版
 找回密码
 立即注册
首页 社区 移动 Protocol Buffers(Objective-C)踩坑指南

Protocol Buffers(Objective-C)踩坑指南

猿梦 2022-11-20 04:29:40
椅子覃白曼对#本尊小东一些%这篇文章是讲如何把protobuf文件的编译工作集成到Xcode中,达到在Xcode中就像添加一般的OC文件一样不进行任何多余的操作直接编译运行.proto文件的目的。牛逼,这么智能吗?是的,就是这么智能!笔者的公司现在所有端都在统一使用一套protobuf数据结构,免除了多端重复定义同一套数据结构的重复工作,效率很高,非常值得推荐。并且Xcode 10进行了一些小优化来增加了对Protobuf的支持,相信不久以后,Xcode对Protobuf的支持将更加智能!至于什么是 Protobuf 和 Protobuf 语法教程,不是这篇文章的主题,请自行Google。环境:Xcode 10+语言:Objective-C话不多说,正题开始:首先,真正的企业级项目,并不只是网上很多教程里面演示的一两个  .proto  文件,而是一批  .proto  文件目录的集合,并且是多端共享的。你会发现按照那些教程里面的讲的去做写个demo或许可以,但是真正要达到企业级别的使用的时候,还远远不够,你会遇到各种各样的坑。别问我是怎么知道的,我都是靠自己一个个踩出来的。首先,要能编译Protobuf文件,我们得安装官方的编译器。你可以选择下面任意一种你喜欢的安装方式:安装好后,在terminal中输入 which protoc 检测是否安装成功,如安装成功会返回文件路径:  /usr/local/bin/protoc如有问题,请自行google,不在本教程范围内。没什么好说的,新建一个Xcode工程。使用Cocoapods引入Protobuf的库:Pod search Protobuf选择最稳定的版本即可。这里有两种创建.proto文件的方式:至于文件内容,如果你熟悉protobuf语法,那随便写几行即可,如果不熟悉,那么可以copy我的测试内容:A.proto  文件内容:B.proto  文件内容:Xcode 自己并不认识 .proto文件,所以并不会自动编译它们,我们需要把 .proto编译器 自己集成到项目当中,集成的方式如下:Project --> Build Rules --> 点击+号 ,生成一个特定文件类型编译脚本。比如:到此处,我们有几个注意事项:我们试试把  --proto_path  换成相对路径,看会发生什么,也就是把脚本换成编译运行,咦~报错了。查看日志,我们可以看到这么一条log信息:翻译过来就是在--proto_path这个参数中你必须指定.proto源文件的精确路径, protoc 太笨了,它无法搞清楚这个相对路径是不是我们要的绝对路径。google的工程师说这太他么难了。所以这里很明确了, --proto_path  的参数值,只能是proto文件根目录的绝对路径。我们上面说了,${INPUT_FILE_PATH} 是代表编译输入源文件的绝对路径。文档里面给的demo是:protoc --proto_path=src --objc_out=build/gen src/foo.proto src/bar/baz.proto什么意思呢?它说,最终编译器会把 src/foo.proto 文件编译成: build/gen/Foo.pbobjc.h  和  build/gen/Foo.pbobjc.m  文件。而会把  src/bar/baz.proto  文件编译成  build/gen/bar/Baz.pbobjc.h  和  build/gen/bar/Baz.pbobjc.m 。而不是 build/gen/Baz.pbobjc.h  和   build/gen/Baz.pbobjc.m也就是说protobuf编译器最终生成的文件会自动按照文件源目录结构存放。特别强调并不会自动创建  build/gen  目录,这个目录需要你提前建好。并且,查看最终编译生成的.m文件,你会发现一些有趣的事情;比如我在A.proto中引入了B.proto文件,你会看到Protobuf最终编译出来的A.pbobjc.m文件导入文件的格式是包含文件路径的,例如:我们注意到,上面设置的proto文件的编译输出路径是  $DERIVED_FILE_DIR , 这是为何呢?答案是为了方便Xcode的集成。对于自定义的编译脚本,都需要设置一个文件的输出路径.我们点脚本框下面的Output Files下面的 + 号, 指定文件输出路径。因为OC文件分为.h和.m文件,所以我们指定2个。点了之后,你会发现,xcode默认给出的是  $(DERIVED_FILE_DIR)/newOutputFile ,我们将其改为 $(DERIVED_FILE_DIR)/${INPUT_FILE_BASE}.pbobjc.h  和  $(DERIVED_FILE_DIR)/${INPUT_FILE_BASE}.pbobjc.m ,并且在.m文件的 Compiler Flags 中指定为 -fno-objc-arc 代表该.m文件采用mrc编译。编译运行,大功告成,是不可能的!!!!你会发现又报错了:什么意思呢? 其实就是在  DerivedSources  下找不到  A.pbobjc.m  文件。因为我们指定这个编译的输出路径在这个目录下,所以Xcode在进行OC文件的编译时会去这个目录下找,但是它找不到。为什么找不到呢?我们去这个目录下看,这个目录下确实没有  A.pbobjc.m  这个文件,但是确发现有  a/A.pbobjc.m 。原因我们已经说了,protoc最终的编译文件会自动加上目录前缀。有人可能会说,能不能把输出文件改成  $(DERIVED_FILE_DIR)/*/${INPUT_FILE_BASE}.pbobjc.h  呢?那我们就来试下。编译运行what the hell?原来,Xcode的Output Files特别蠢,它不支持类似这种通配符写法:  $(DERIVED_FILE_DIR)/*/${INPUT_FILE_BASE}.pbobjc.h 。也不支持传入任何的自定义变量。只能是明确的文件路径和Xcode自带的环境变量,但是实际项目中,可能不只一层路径,有可能是文件夹下嵌套文件夹。靠,那这怎么办呢?实在没办法了,就在打算放弃的时候,咨询了我们的脚本大神,我们尝试了以下在脚本末尾再加了两行:是不是很机智?什么意思呢?就是说我们cd到该目录,然后找到该文件对应生成的oc文件,将其copy一份儿到根目录。怀着求神拜佛的意志,运行了以下,Perfect,终于不再报错了,到目录中查看,也正是我们想要的,所有文件都被copy出来了。下一步,就是正常的在项目中import和使用了。你以为到此就没有坑了吗?到此还有坑。有2点需要注意:好了,就讲到这里吧,如果觉得文章看得不是很明白,需要一个demo。或者大神有更好的建议,请在评论区留言~如果文章对你有帮助,请不要吝啬你的点赞哦,你的支持是我分享的动力~如果大家喜欢,有时间再讲讲怎么改改AFNetworking,能直接请求后端给的 Protobuf 格式的数据~

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册