问题背景
Xcode由8.3.3升级到9.0,原先在Xcode8.3.3能编译并运行成功的项目,在Xcode9.0编译失败,出现如下错误:
在FMDatabase.m中:
前一篇文章讲到sqlcipher数据库加密的配置教程是没有问题的,问题在于Implicit declaration of funciton,字面意思叫隐式声明,我们理解为,在当前文件FMDatabase.m以及它内部#import的文件中,只找到了function的实现,并没有找到头文件和其声明。这是升级Xcode9.0后,C99编译环境导致的。
问题排查
我们可以将这归为一类问题,Implicit declaration of funciton ‘xxx’ is invalid in C99,这类问题的解决办法一般是:
找到这个‘xxx’方法被调用的**.m文件
这里sqlite3_key和sqlite3_rekey是在FMDatabase.m文件中使用
在**.m中找到‘xxx’是引用自哪一个文件
这里sqlite3_key和sqlite3_rekey的声明源自#import < sqlite3.h >
确定‘xxx’方法在这个文件中已经被正确声明
这里sqlite3.h文件存在sqlite3_key和sqlite3_rekey的声明确实存在于sqlcipher/Source/目录下,
但是#import < sqlite3.h >显然无法正确链接到该位置,
按住‘command’,用鼠标点击#import < sqlite3.h > ,Jump to defination,
发现#import < sqlite3.h >链接到了iOS11.0/usr/include/sqlite3.h文件下,而该文件中不存在sqlite3_key和sqlite3_rekey的声明。
至此,我们就找到隐式声明的问题所在了。
解决办法
修改链接路径,使其引用自正确的文件
以本文的问题为例,既然是链接文件出错,那么我们通过修改#import < sqlite3.h > 改为#import < SQLCipher/sqlite3.h > ,让其链接到sqlcipher下的sqlite3.h文件,可以解决这个问题
注意,如果像我们上一篇文章,是通过静态库来配置SQLCipher,是找不到< SQLCipher/sqlite3.h>路径的,我们可以通过强制打破隐式声明的方式解决这个问题,在FMDatabase.m中声明sqlite3_key和sqlite3_rekey:
#if defined(SQLITE_HAS_CODEC)
SQLITE_API int sqlite3_key(sqlite3 *db, const void *pKey, int nKey);
SQLITE_API int sqlite3_rekey(sqlite3 *db, const void *pKey, int nKey);
#endif