The iOS SDK is called BmobSDK, and is written in Objective-Cframework; Swift projects use it through Bridging Header bridging. The SDK data model is centered on BmobObject , and you do not need to write a subclass for each table (unlike Android).
Core Principles
1. Install the SDK — CocoaPods strongly recommended:
# Podfile
target "你的项目名称" do
platform :ios, "15.6"
use_frameworks!
pod 'BmobSDK'
end
pod install
After installationonly open
.xcworkspace, do not open.xcodeprojagain, otherwise the library introduced by Pods cannot be found.
You can also manually import BmobSDK.xcframework, and link the following system libraries (see references/install.md)。
2. Swift must bridge: Create any .m file to make Xcode pop up "Create Bridging Header", then in the generated 项目名-Bridging-Header.h add:
#import <BmobSDK/Bmob.h>
3. Initialization (OC) — AppDelegate.m:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// release 上线时启用备案域名,必须在 registerWithAppKey 之前
// [Bmob resetDomain:@"https://你的备案域名"];
[Bmob registerWithAppKey:@"你的Application ID"];
return YES;
}
3. Initialization (Swift / SwiftUI) — AppApp.swift:
@main
struct MyApp: App {
init() {
Bmob.register(withAppKey: "你的Application ID")
}
var body: some Scene { WindowGroup { ContentView() } }
}
4. Domain reset (mandatory before launch): The Ministry of Industry and Information Technology requires that a filed domain be used for official launch:
Bmob.resetDomain("https://sdk.yourapp.com") // 必须在 register 前
Bmob.register(withAppKey: "...")
On the OC side use [Bmob resetDomain:@"https://sdk.yourapp.com"];。
5. Do not hardcode the Master Key into the App bundle. On the client only use the Application ID (configure Secret Key + encrypted authorization if necessary).
Security Checklist
- disable debug output in release: during testing
[Bmob setDebug:YES], remove it before release. - App Transport Security(ATS): if the filed domain is HTTP (not recommended), you need to add
Info.plistinNSAppTransportSecurity → NSAllowsArbitraryLoads = YES, but App Store review may reject it; use HTTPS whenever possible. - Tables written to must be configured with ACL: otherwise any user can modify any row.
- Do not commit the real AppKey in the Bridging Header: inject it via a configuration file / xcconfig / environment.
- Replace the filed domain before release: see "4. Domain reset" above.
Common Issues
Cross-platform Q&A:shared/faq.md。
Anti-patterns
See shared/anti-patterns.md. Key points for this platform: do not commit the real AppKey; use HTTPS for ATS whenever possible.
Single-record CRUD (modern Swift style)
Add
let gameScore = BmobObject(className: "GameScore")
gameScore.setObject("John Smith", forKey: "playerName")
gameScore.setObject(90, forKey: "score")
gameScore.setObject(false, forKey: "cheatMode")
gameScore.saveInBackground { (isSuccessful, error) in
if let error = error {
print("保存失败: \(error.localizedDescription)")
} else {
print("保存成功: \(gameScore.objectId ?? "")")
}
}
Query a single record
let bquery = BmobQuery(className: "GameScore")
bquery.getObjectInBackground(withId: "0c6db13c") { (object, error) in
if let error = error { print(error); return }
guard let object = object else { return }
let playerName = object.object(forKey: "playerName") as? String
let score = object.object(forKey: "score") as? NSNumber
print(playerName ?? "", score ?? 0)
}
Update (by objectId)
let gameScore = BmobObject(outDatatWithClassName: "GameScore", objectId: "0c6db13c")
gameScore.setObject(91, forKey: "score")
gameScore.updateInBackground { (isSuccessful, error) in
if let error = error { print(error) }
}
Note that the API name is
outDatatWithClassName(spelling is a historical leftover, do not change it) — theBmobObjectobtained with this method will not send a GET query first, and can be used directly for update / delete.
Delete
let gameScore = BmobObject(outDatatWithClassName: "GameScore", objectId: "0c6db13c")
gameScore.deleteInBackground { (isSuccessful, error) in /* ... */ }
Query list (with conditions + sorting + pagination)
let query = BmobQuery(className: "GameScore")
query.whereKey("score", greaterThan: 100)
query.orderByDescending("createdAt")
query.limit = 20
query.skip = 0
query.findObjectsInBackground { (array, error) in
guard let results = array as? [BmobObject] else { return }
for obj in results {
print(obj.objectId ?? "", obj.object(forKey: "playerName") ?? "")
}
}
Single-record CRUD (Objective-C)
// 添加
BmobObject *gameScore = [BmobObject objectWithClassName:@"GameScore"];
[gameScore setObject:@"小明" forKey:@"playerName"];
[gameScore setObject:@78 forKey:@"score"];
[gameScore setObject:[NSNumber numberWithBool:YES] forKey:@"cheatMode"];
[gameScore saveInBackgroundWithResultBlock:^(BOOL isSuccessful, NSError *error) {
// ...
}];
// 查询单条
BmobQuery *bquery = [BmobQuery queryWithClassName:@"GameScore"];
[bquery getObjectInBackgroundWithId:@"0c6db13c"
block:^(BmobObject *object, NSError *error) {
if (object) {
NSString *playerName = [object objectForKey:@"playerName"];
BOOL cheat = [[object objectForKey:@"cheatMode"] boolValue];
NSLog(@"%@ %d", playerName, cheat);
}
}];
// 更新(不预先 GET,直接构造 + objectId)
BmobObject *gs = [BmobObject objectWithoutDatatWithClassName:@"GameScore" objectId:@"0c6db13c"];
[gs setObject:@91 forKey:@"score"];
[gs updateInBackground];
// 删除
BmobObject *gs = [BmobObject objectWithoutDatatWithClassName:@"GameScore" objectId:@"0c6db13c"];
[gs deleteInBackground];
Integration with MCP
If already configured Bmob MCP, first get_project_tables to get the real schema, avoiding:
- misspelled field names (
setObject:forKey:does not validate the schema) - mixing BmobObject with BmobUser
Troubleshooting Quick Reference
For cross-platform phenomena, first check shared/faq.md。
| Symptom | Troubleshooting |
|---|---|
| 100 error | The request content (query conditions) is incorrect |
| 20003 none objectid | Update / delete / query a single record without passing objectId |
| 20004 none object | Query result is empty |
| 20006 cloud function failed | Cloud function execution error |
| 20017 init not finish | In register the SDK was called before completion; check the init {} order |
| Swift "use of undeclared identifier 'BmobObject'" | Bridging Header not created or not #import <BmobSDK/Bmob.h> |
| Xcode 14+ cannot find the Pod library | Opened .xcodeproj instead of .xcworkspace |
| App Store review rejection ATS | Change the registered domain to HTTPS, remove NSAllowsArbitraryLoads |
| release build requests rejected / 403 | No SDK-type registered domain configured; or resetDomain call order is wrong (must be before register ) |
| 9015 | Fallback error code; be sure to read the response description |
Advanced capabilities (read references/ as needed)
| Topic | Path |
|---|---|
| End-to-end scenarios | shared/recipes/ |
| BmobDocs sync code snippets | references/snippets/ |
| Complete installation + Bridging + framework linking + ATS configuration | references/install.md |
| Advanced queries (or / subquery / geolocation / include) | references/query.md |
| Pointer / Relation | references/pointer-and-relation.md |
| User system / SMS / third-party login | (P1: bmob-auth-ios) |
| File upload / BmobFile | (P1: bmob-storage-ios) |
Reference
- OC complete API:develop_doc.md
- Swift complete API:swift_develop_doc.md
- Swift Quickstart:swift_quick_start.md
- SDK source code:https://github.com/bmob/Bmob-iOS-SDK
- Swift Demo:https://github.com/bmob/bmob-ios-demo/blob/master/SwiftDemo.zip
- Error codes:
bmob-error-codes - MCP integration:
bmob-mcp