import sqlite3.h error: include of non-modular header inside framework module
import sqlite3.h error: include of non-modular header inside framework module
我正在为我的应用程序创建一个自定义 back-end 框架,它封装了我所有与数据库相关的逻辑,因此,当我们要使用任何数据库操作时,我们只需要调用该框架函数。
现在,对于数据库操作,我需要在名为 Data.swift 的文件中 #import <sqlite3.h>
,我的所有数据库函数都存在于该文件中。但这是 swift 文件,所以我如何导入 sqlite..?
当我使用 bridging-header.h 时,我收到错误消息
error: using bridging headers with framework targets is unsupported
bridging-header.h 里面有 #import <sqlite3.h>
并设置桥接 Header 变量。
如果我在 Umbrella header 中添加 import 语句,这会给我错误
include of non-modular header inside framework module
我用谷歌搜索了很多,但找不到合适的答案。我也看了 https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_82 并正确地遵循了它,但我想我还是错过了一些东西。
请给我一些建议。
据我所知,您无法在框架中直接将 Objective-C 文件导入 Swift。但是您可以在同一框架中的另一个 Objective-C classes 中完成。因此,如果您在框架中编写 Objective-C class,您将能够将 header 文件直接包含到 class 中并使用它。
出于同样的目的,我最终在 Objective-C 中为 sqlite.h
编写了一个包装器 class,然后在我的 Swift 代码中访问它。您编写的 class 包装器 header 必须制作 public 并添加到您的保护伞 header.
我写的是这样的:
#ifndef SqlWrapper_h
#define SqlWrapper_h
struct sqlite3;
BOOL OpenDatabaseWithFileName(NSString* databaseFileName, struct sqlite3** database);
BOOL PrepareStatement(struct sqlite3* database,NSString *selectStatement,struct sqlite3_stmt** preparedStatement);
BOOL StepStatement(struct sqlite3_stmt* compiledStatement);
BOOL FinalizeStatement(struct sqlite3_stmt* compiledStatement);
NSInteger NumberOfRowsAffected(struct sqlite3* database);
NSInteger LastInsertedRowID(struct sqlite3* database);
NSInteger GetColumnCount(struct sqlite3_stmt* compiledStatement);
const unsigned char* GetColumnValue(struct sqlite3_stmt* compiledStatement,int index);
NSInteger GetColumnValueInInteger(struct sqlite3_stmt* compiledStatement,int index);
double GetColumnValueInDouble(struct sqlite3_stmt* compiledStatement,int index);
BOOL CloseDatabase(struct sqlite3* database);
#endif
这些函数中的每一个都包装了 sqlite3 方法。这些可以在同一框架中从您的 Swift classes 中调用。
我获取了一个 objective c 文件并对其进行了一些自定义。
Sqlite3Wrapper.h
#ifndef SqliteWrap_Sqlite3Wrapper_h
#define SqliteWrap_Sqlite3Wrapper_h
struct sqlite3;
@class SqlStatement;
@interface Sqlite3Wrapper : NSObject
-(id)initWithFileName: (NSString*) databaseFileName;
-(BOOL) openDatabase;
-(BOOL) closeDatabase;
-(BOOL) isOpen;
-(BOOL) executeStatement: (NSString*) sqlStatement;
-(SqlStatement*) prepareStatement: (NSString*) sqlStatement;
@end
#endif
Sqlite3Wrapper.m
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#import "Sqlite3Wrapper.h"
#import "SqlStatement.h"
@implementation Sqlite3Wrapper {
sqlite3* _database;
NSString* _databaseFileName;
}
-(id) initWithFileName:(NSString *)databaseFileName {
self = [super init];
if (self) {
_databaseFileName = databaseFileName;
}
return self;
}
-(BOOL) openDatabase {
int returnValue = sqlite3_open([_databaseFileName UTF8String], &_database);
if (returnValue == SQLITE_OK) {
return YES;
}
return NO;
}
-(BOOL) closeDatabase {
if (_database) {
if (sqlite3_close(_database) == SQLITE_OK) {
_database = nil;
return YES;
}
}
return NO;
}
-(BOOL) isOpen {
return (_database != nil);
}
-(BOOL) executeStatement: (NSString *)sqlStatement {
if (_database == nil) {
return NO;
}
return (sqlite3_exec(_database, [sqlStatement UTF8String], nil, nil, nil) == SQLITE_OK);
// sqlite3_stmt* statement;
// if (sqlite3_prepare_v2(_database, [sqlStatement UTF8String], -1, &statement, nil) == SQLITE_OK) {
// BOOL success = (sqlite3_step(statement) == SQLITE_OK);
// sqlite3_finalize(statement);
// return success;
// }
// return NO;
}
-(SqlStatement*) prepareStatement:(NSString *)sqlStatement {
if (_database == nil) {
return nil;
}
sqlite3_stmt* pStmt = nil;
if (sqlite3_prepare_v2(_database, [sqlStatement UTF8String], -1, &pStmt, nil) == SQLITE_OK) {
return [[SqlStatement alloc] initWithStatement: pStmt];
}
return nil;
}
@end
我正在使用这个包装文件并创建了一个 swift 文件。
Logger.swift
import Foundation
public class Logger {
var dbWrapper:Sqlite3Wrapper
var dataAccess = [String:AnyObject]()
public init(dbName:String) {
let docDirPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let dbPath:NSString = docDirPath.stringByAppendingString(dbName)
let fileManager:NSFileManager = NSFileManager.defaultManager()
dbWrapper = Sqlite3Wrapper(fileName: dbName)
if !fileManager.fileExistsAtPath(dbPath) {
if dbWrapper.openDatabase() == false {
NSLog("Database not opened")
let sql:NSString = "CREATE TABLE IF NOT EXISTS CONTACTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT, PHONE TEXT)"
if dbWrapper.executeStatement(sql) {
NSLog("Table Created")
}
dbWrapper.closeDatabase()
} else {
NSLog("Database opened")
}
} else {
NSLog("Database exists")
}
}
public func open() -> Bool {
return dbWrapper.openDatabase()
}
public func test(dbName:NSString) {
let docDirPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let dbPath:NSString = docDirPath.stringByAppendingString(dbName)
let fileManager:NSFileManager = NSFileManager.defaultManager()
if !fileManager.fileExistsAtPath(dbPath) {
if Sqlite3Wrapper(fileName: dbPath) == false {
NSLog("Database not opened")
let sql:NSString = "CREATE TABLE IF NOT EXISTS CONTACTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT, PHONE TEXT)"
if dbWrapper.executeStatement(sql) {
NSLog("Table Created")
}
dbWrapper.closeDatabase()
} else {
NSLog("Database opened")
}
} else {
NSLog("Database exists")
}
}
}
public func logMessage(message: NSString ) {
NSLog("Message is printed")
}
public func createDatabase(dbName: NSString ) {
Data(dbName: dbName)
}
最后两个函数 createDatabase
和 logMessage
只是临时测试我是否可以直接访问这些函数。
我还为设备和模拟器创建了一个 "Aggregated Target" 通用框架。但是当我使用这个通用框架时,我无法 import Logger
并收到错误 "No such module 'Logger'"。但是当我为设备打包框架并尝试添加相同的框架时,我能够执行导入操作。
最后,问题是一旦我 import Logger
,我无法从框架访问任何功能或 Data
class。我只能访问写在Objective C中的Sqlite3Wrapper
。我想使用该数据 class 或 public 函数。
如果您认为我做错了什么,请告诉我。
我正在为我的应用程序创建一个自定义 back-end 框架,它封装了我所有与数据库相关的逻辑,因此,当我们要使用任何数据库操作时,我们只需要调用该框架函数。
现在,对于数据库操作,我需要在名为 Data.swift 的文件中 #import <sqlite3.h>
,我的所有数据库函数都存在于该文件中。但这是 swift 文件,所以我如何导入 sqlite..?
当我使用 bridging-header.h 时,我收到错误消息
error: using bridging headers with framework targets is unsupported
bridging-header.h 里面有 #import <sqlite3.h>
并设置桥接 Header 变量。
如果我在 Umbrella header 中添加 import 语句,这会给我错误
include of non-modular header inside framework module
我用谷歌搜索了很多,但找不到合适的答案。我也看了 https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-XID_82 并正确地遵循了它,但我想我还是错过了一些东西。
请给我一些建议。
据我所知,您无法在框架中直接将 Objective-C 文件导入 Swift。但是您可以在同一框架中的另一个 Objective-C classes 中完成。因此,如果您在框架中编写 Objective-C class,您将能够将 header 文件直接包含到 class 中并使用它。
出于同样的目的,我最终在 Objective-C 中为 sqlite.h
编写了一个包装器 class,然后在我的 Swift 代码中访问它。您编写的 class 包装器 header 必须制作 public 并添加到您的保护伞 header.
我写的是这样的:
#ifndef SqlWrapper_h
#define SqlWrapper_h
struct sqlite3;
BOOL OpenDatabaseWithFileName(NSString* databaseFileName, struct sqlite3** database);
BOOL PrepareStatement(struct sqlite3* database,NSString *selectStatement,struct sqlite3_stmt** preparedStatement);
BOOL StepStatement(struct sqlite3_stmt* compiledStatement);
BOOL FinalizeStatement(struct sqlite3_stmt* compiledStatement);
NSInteger NumberOfRowsAffected(struct sqlite3* database);
NSInteger LastInsertedRowID(struct sqlite3* database);
NSInteger GetColumnCount(struct sqlite3_stmt* compiledStatement);
const unsigned char* GetColumnValue(struct sqlite3_stmt* compiledStatement,int index);
NSInteger GetColumnValueInInteger(struct sqlite3_stmt* compiledStatement,int index);
double GetColumnValueInDouble(struct sqlite3_stmt* compiledStatement,int index);
BOOL CloseDatabase(struct sqlite3* database);
#endif
这些函数中的每一个都包装了 sqlite3 方法。这些可以在同一框架中从您的 Swift classes 中调用。
我获取了一个 objective c 文件并对其进行了一些自定义。
Sqlite3Wrapper.h
#ifndef SqliteWrap_Sqlite3Wrapper_h
#define SqliteWrap_Sqlite3Wrapper_h
struct sqlite3;
@class SqlStatement;
@interface Sqlite3Wrapper : NSObject
-(id)initWithFileName: (NSString*) databaseFileName;
-(BOOL) openDatabase;
-(BOOL) closeDatabase;
-(BOOL) isOpen;
-(BOOL) executeStatement: (NSString*) sqlStatement;
-(SqlStatement*) prepareStatement: (NSString*) sqlStatement;
@end
#endif
Sqlite3Wrapper.m
#import <Foundation/Foundation.h>
#import <sqlite3.h>
#import "Sqlite3Wrapper.h"
#import "SqlStatement.h"
@implementation Sqlite3Wrapper {
sqlite3* _database;
NSString* _databaseFileName;
}
-(id) initWithFileName:(NSString *)databaseFileName {
self = [super init];
if (self) {
_databaseFileName = databaseFileName;
}
return self;
}
-(BOOL) openDatabase {
int returnValue = sqlite3_open([_databaseFileName UTF8String], &_database);
if (returnValue == SQLITE_OK) {
return YES;
}
return NO;
}
-(BOOL) closeDatabase {
if (_database) {
if (sqlite3_close(_database) == SQLITE_OK) {
_database = nil;
return YES;
}
}
return NO;
}
-(BOOL) isOpen {
return (_database != nil);
}
-(BOOL) executeStatement: (NSString *)sqlStatement {
if (_database == nil) {
return NO;
}
return (sqlite3_exec(_database, [sqlStatement UTF8String], nil, nil, nil) == SQLITE_OK);
// sqlite3_stmt* statement;
// if (sqlite3_prepare_v2(_database, [sqlStatement UTF8String], -1, &statement, nil) == SQLITE_OK) {
// BOOL success = (sqlite3_step(statement) == SQLITE_OK);
// sqlite3_finalize(statement);
// return success;
// }
// return NO;
}
-(SqlStatement*) prepareStatement:(NSString *)sqlStatement {
if (_database == nil) {
return nil;
}
sqlite3_stmt* pStmt = nil;
if (sqlite3_prepare_v2(_database, [sqlStatement UTF8String], -1, &pStmt, nil) == SQLITE_OK) {
return [[SqlStatement alloc] initWithStatement: pStmt];
}
return nil;
}
@end
我正在使用这个包装文件并创建了一个 swift 文件。
Logger.swift
import Foundation
public class Logger {
var dbWrapper:Sqlite3Wrapper
var dataAccess = [String:AnyObject]()
public init(dbName:String) {
let docDirPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let dbPath:NSString = docDirPath.stringByAppendingString(dbName)
let fileManager:NSFileManager = NSFileManager.defaultManager()
dbWrapper = Sqlite3Wrapper(fileName: dbName)
if !fileManager.fileExistsAtPath(dbPath) {
if dbWrapper.openDatabase() == false {
NSLog("Database not opened")
let sql:NSString = "CREATE TABLE IF NOT EXISTS CONTACTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT, PHONE TEXT)"
if dbWrapper.executeStatement(sql) {
NSLog("Table Created")
}
dbWrapper.closeDatabase()
} else {
NSLog("Database opened")
}
} else {
NSLog("Database exists")
}
}
public func open() -> Bool {
return dbWrapper.openDatabase()
}
public func test(dbName:NSString) {
let docDirPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
let dbPath:NSString = docDirPath.stringByAppendingString(dbName)
let fileManager:NSFileManager = NSFileManager.defaultManager()
if !fileManager.fileExistsAtPath(dbPath) {
if Sqlite3Wrapper(fileName: dbPath) == false {
NSLog("Database not opened")
let sql:NSString = "CREATE TABLE IF NOT EXISTS CONTACTS (ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME TEXT, ADDRESS TEXT, PHONE TEXT)"
if dbWrapper.executeStatement(sql) {
NSLog("Table Created")
}
dbWrapper.closeDatabase()
} else {
NSLog("Database opened")
}
} else {
NSLog("Database exists")
}
}
}
public func logMessage(message: NSString ) {
NSLog("Message is printed")
}
public func createDatabase(dbName: NSString ) {
Data(dbName: dbName)
}
最后两个函数 createDatabase
和 logMessage
只是临时测试我是否可以直接访问这些函数。
我还为设备和模拟器创建了一个 "Aggregated Target" 通用框架。但是当我使用这个通用框架时,我无法 import Logger
并收到错误 "No such module 'Logger'"。但是当我为设备打包框架并尝试添加相同的框架时,我能够执行导入操作。
最后,问题是一旦我 import Logger
,我无法从框架访问任何功能或 Data
class。我只能访问写在Objective C中的Sqlite3Wrapper
。我想使用该数据 class 或 public 函数。
如果您认为我做错了什么,请告诉我。