[英]iOS App crashes in Release Mode but not in debug (using MongoDB and Stitch SDK)
I'm using MongoDB and Stitch SDK (StitchSDK ver. 6.4.0).我正在使用 MongoDB 和 Stitch SDK(StitchSDK 版本 6.4.0)。 My app for iPhone runs in debug mode but when I build it as release and install it via TestFlight, it crashes.我的 iPhone 应用程序在调试模式下运行,但当我将其构建为发行版并通过 TestFlight 安装时,它崩溃了。 I tried changing the optimisation level in the build settings, but no luck.我尝试更改构建设置中的优化级别,但没有成功。
The part of the Device Log which refers to the Crashed Thread is the following:设备日志中涉及崩溃线程的部分如下:
Thread 8 name: Dispatch queue: com.apple.root.default-qos
Thread 8 Crashed:
0 bson 0x105f72748 bson_append_array + 120
1 MongoSwift 0x105829db0 Array.encode(to:forKey:) + 1388
2 MongoSwift 0x105829db0 Array.encode(to:forKey:) + 1388
3 MongoSwift 0x10582c484 protocol witness for BSONValue.encode(to:forKey:) in conformance [A] + 24
4 MongoSwift 0x10583ff50 specialized Document.init(dictionaryLiteral:) + 668
5 MongoSwift 0x10583c6b8 Document.init(dictionaryLiteral:) + 24
6 StitchCoreSDK 0x105d27788 CoreStitchServiceClientImpl.getCallServiceFunctionRequest(withName:withArgs:withTimeout:) + 220
7 StitchCoreSDK 0x105d27db0 CoreStitchServiceClientImpl.callFunction<A>(withName:withArgs:withRequestTimeout:) + 120
8 StitchCoreSDK 0x105d28414 protocol witness for CoreStitchServiceClient.callFunction<A>(withName:withArgs:withRequestTimeout:) in conformance CoreStitchServiceClientImpl + 16
9 StitchCoreRemoteMongoDBService 0x105bd06d0 CoreRemoteMongoReadOperation.executeRead() + 232
10 StitchCoreRemoteMongoDBService 0x105bd05cc CoreRemoteMongoReadOperation.toArray() + 12
11 StitchRemoteMongoDBService 0x105e8598c partial apply for closure #1 in RemoteMongoReadOperation.toArray(_:) + 28
12 StitchRemoteMongoDBService 0x105e859b0 partial apply for thunk for @escaping @callee_guaranteed () -> (@owned [A], @error @owned Error) + 24
13 StitchCore 0x105ae410c closure #1 in OperationDispatcher.run<A>(withCompletionHandler:_:) + 136
14 StitchCore 0x105ae3e44 thunk for @escaping @callee_guaranteed () -> () + 20
15 libdispatch.dylib 0x1844f91a4 _dispatch_call_block_and_release + 24
16 libdispatch.dylib 0x1844fa1a8 _dispatch_client_callout + 16
17 libdispatch.dylib 0x18449c1fc _dispatch_queue_override_invoke + 728
18 libdispatch.dylib 0x1844a943c _dispatch_root_queue_drain + 340
19 libdispatch.dylib 0x1844a9c38 _dispatch_worker_thread2 + 172
20 libsystem_pthread.dylib 0x1def1fe48 _pthread_wqthread + 224
21 libsystem_pthread.dylib 0x1def1f9f0 start_wqthread + 8
I hope someone can help me out!我希望有人能帮助我!
I made a workaround to send everything as text (json stringify) to the function and then in the function convert it back to json. It is not perfect but it works.我做了一个解决方法,将所有内容作为文本 (json stringify) 发送到 function,然后在 function 中将其转换回 json。它并不完美,但它可以工作。 Here is some code if somebody wants to do the same, I also upgraded to realm, but the principle stays the same:如果有人想这样做,这里有一些代码,我也升级到 realm,但原理保持不变:
// the part in the IOS app
let app = App(id: "yourapp");
app.login(credentials: Credentials.anonymous) {
(result) in
DispatchQueue.main.async{
switch result{
case .failure(let error):
print("login failed: \(error)")
case .success(let user):
print("Login as \(user) succeeded !")
var arrayPlog = [Logj]();
//let encoder = BSONEncoder() // does not work
// logs
let jsonObjectLog: [String : Any] = [
"logs": self.parseLogs(&arrayPlog)
]
let jsonData = try? JSONSerialization.data(withJSONObject: jsonObjectLog, options: [])
let jsonString = String(data: jsonData!, encoding: String.Encoding.utf8)
// user
let jsonObjectUser: [String : Any] = [
"user": self.getUserInfo()
]
let jsonDataUser = try? JSONSerialization.data(withJSONObject: jsonObjectUser, options: [])
let jsonStringUser = String(data: jsonDataUser!, encoding: String.Encoding.utf8)
// call realm function
user.functions.AddData([AnyBSON(jsonString!),AnyBSON(jsonStringUser!)]){ Adddata, error in
guard error == nil else {
print("error")
return
}
print ("function called")
}
}
}
}
// as a sample the getUserInfo function
func getUserInfo() -> [String : Any?]{
let dictionary = Bundle.main.infoDictionary!
let version = dictionary["CFBundleShortVersionString"] as! String
let build = dictionary["CFBundleVersion"] as! String
let firmwareBuild = SettingsManager.sharedInstance.get(.sensorFirmwareVersion)
let jsonObject : [String : Any?] = [
"user_code" : SettingsManager.sharedInstance.get(.deviceUUID) ?? "",
"sensor_fw_version": firmwareBuild,
"sensor_mac_address": SettingsManager.sharedInstance.get(.sensorMacAddress) ?? ""
]
return jsonObject
}
// the AddData function in mongoDB
exports = async function(log,user){
/*
Accessing application's values:
var x = context.values.get("value_name");
Accessing a mongodb service:
var collection = context.services.get("mongodb-atlas").db("dbname").collection("coll_name");
var doc = collection.findOne({owner_id: context.user.id});
To call other named functions:
var result = context.functions.execute("function_name", arg1, arg2);
Try running in the console below.
*/
console.log(" begin of function ")
var success = 1; // do not use a boolean because maybe clients do not support it
try {
// USERS PART
const atlas = context.services.get('mongodb-atlas');
var retVal = "empty";
var res = null;
var users = atlas.db("yourDB").collection("users");
if (Array.isArray(user)) // needed for IOS
{
user = user[0];
}
console.log(typeof user);
console.log(typeof log)
console.log("before parse user:" + user)
console.log("before parse log:" + log)
if (typeof user == "string") // to fix the ios BSON bug..
{
const objUser = JSON.parse(user);
const objLog = JSON.parse(log);
user = objUser.user
log = objLog.logs
}
res = await atlas.db('yourDB').collection('users').find({ user_code: user.user_code}).limit(10).toArray();
console.log(res)
if (res.length > 1)
{
res[0] = res[res.length-1]; // see if we can remove this replace one will probably replace the first one anyway
//errorstr = "user has more then 1 user entrys, using the last one"
}
var updated_at = Date();
var created_at = null;
if (res.length==0)
{
created_at = Date();
}
else
{
created_at = res[0].created_at;
}
user.created_at = created_at;
user.update_at = updated_at;
var createdUserData = await users.replaceOne({user_code: user.user_code},user,{upsert: true}); // replace if already existed else create new one
console.log("created User: " + createdUserData)
// createdUserData does not return the created data so ask for it because we need the id of the record.
// upsertedId should be available according documentation but I could not make it work
// res[0] should always exist by now
res = await atlas.db('yourDB').collection('users').find({ user_code: user.user_code}).limit(1).toArray(); // just ask the latest
console.log("res :" + res)
// LOGS PART
created_at = Date(); // created data is always new for the _logs there are no updates of a record only new ones
var logs = await atlas.db('yourDB').collection('_logs')
// so logs are the complete logs in the DB, log is the current entry that needs to be put in the DB
if (Array.isArray(log))
{
console.log("array of log")
var i = 0;
for (i=0; i< log.length ; i++)
{
log[i].user_id = res[0]._id;
log[i].creation_at = created_at;
log[i].update_at = updated_at;
await logs.insertOne(log[i]);
}
}
else
{
console.log("single log")
log.user_id = res[0]._id; // link user_id of this log with the _id of the user in the users-collection
console.log("log extended with user_id :" + log)
log.creation_at = created_at;
log.update_at = updated_at;
console.log("before insertone :" + log)
await logs.insertOne(log);
}
console.log(" voor logs find")
res = await logs.find({ user_id: res[0]._id }).limit(100).toArray();
console.log(" na logs find")
if (Array.isArray(res))
retVal = res;
}catch(error)
{
console.log("error in function")
success = 0;
}
return success;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.