简体   繁体   中英

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). My app for iPhone runs in debug mode but when I build it as release and install it via TestFlight, it crashes. 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. Here is some code if somebody wants to do the same, I also upgraded to realm, but the principle stays the same:

        // 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;
}
            

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM