Support Topics Documentation Slack YouTube Blog

Swift 5 change

Hi

Strange one this

My app running on swift version 3 was retrieving backendless v5.x data correctly.

I have now updated the app to run on swift 5 and something, somewhere along the way has caused the data not to be found correctly. Maybe the code is not correct for swift 5? Perhaps you can see what may be wrong… Conversion to swift 5 syntax is as far as I am aware the only thing which has changed - no code relating to Backendless should have changed, at least not deliberately!

I can find the data objects correctly…
let dataQuery = DataQueryBuilder()
//using custom class approach
let dataStore = backendless?.data.of(LoyaltyPoints().ofClass())

var response = LoyaltyPoints

    Types.tryblock({ () -> Void in
 
        response = dataStore?.find(dataQuery) as! [LoyaltyPoints]
        
        
        while (response.count != 0){
            
            //successfully finds 69 objects here.

            dump(response)  

            //however each response contains nil data
            i.e
           <A2.LoyaltyPoints: 0x283fa8b00> #0
             super: NSObject**
             objectId: nil
             user: nil
             name: nil
             loyaltyPointValue: 0
             etc..



            dataQuery?.prepareNextPage()
            response = dataStore?.find(dataQuery) as! [LoyaltyPoints]
    
        }
        
        
    },
                   catchblock: { (exception) -> Void in
                    // handle error from server here
                    print("Server reported an error")
    })

So it is finding the data objects successfully but there is nothing in there. If I run the same code on Swift V3 it is working correcty so something strange has happened along the way to make all my objects return nil data!

LoyaltyPoints.swift looks like something like this…

import Foundation
class LoyaltyPoints : NSObject {

var objectId : String?
var user: BackendlessUser?
var name : String?
var dateTime: Date?
var created2: Date?
var verified: String? 
var loyaltyPointValue: Int = 0  

}

Hi @mike-turner,

Make sure to add the @objcMembers attribute to your data classes. This is per the API doc:
https://backendless.com/docs/ios/data_data_object.html

Regards,
Mark

Perfect. Fixed.

Thanks for putting me right, and apologies for not seeing that!

Mike

Similar problem I think, probably due to to swift conversion as it was working so keeping on same thread.

It seems the async method does not seem to ever get to the response or show an error either. Nothing, but the sync method seems to work so must be something to do with async methods and/or swift4/5 conversion.

let dataStore = self.backendless?.data.of(DeviceInfo().ofClass())

        dataStore?.find({
            (array) -> () in
            let devicesArray = array as! [DeviceInfo]
            print("did I find anything!").   // never even gets here
            print("Result: \(devicesArray)")
        },
                        error: {
                            (fault : Fault?) -> () in
                            print("Server reported an error: \(fault)")
        })

My DeviceInfo class

@objcMembers
class DeviceInfo : NSObject {

var objectId: String?

var UUID: String?

var OS : String?

var Version: String?

var AppVersion: String?

var loggedIn : Date? //date

var created: NSDate?

var created2: Date?

var updated: NSDate?

}

Hello mike,

please provide your Application ID.

Regards,
Olha

Hi Olha, here you go

App ID : 49F668C0-314F-EB6F-FF03-8813A8AC1900

apologies was testing with this one: 494D0AFB-19A8-43B5-B82F-9A94126D05AC

Everything works fine for me:

@objcMembers class DeviceInfo: NSObject {
    var objectId: String?
    var UUID: String?
    var OS : String?
    var Version: String?
    var AppVersion: String?
    var loggedIn : Date? //date
    var created: NSDate?
    var created2: Date?
    var updated: NSDate?
}
func test() {
    let dataStore = Backendless.sharedInstance().data.of(DeviceInfo().ofClass())
    dataStore?.find({ (array) -> () in
        let devicesArray = array as! [DeviceInfo]
        print("did I find anything!")   // never even gets here
        print("Result: \(devicesArray)")
    }, error: {
        (fault : Fault?) -> () in
        print("Server reported an error: \(fault)")
    })
}

And here is the result:

Please make sure you’ve configured and initialized your app correctly.

Regards,
Olha

Thanks Olha.

This is so frustrating. I know it should work, but it just doesn’t fire

All of my other Backendless functions are working, so I am guessing the app is set up right.

It must be something to do with the async methods and swift 4 changes, but I can’t find it.

Look this method works, there must be some clue here

func test(){
        let dataStore = backendless?.data.of(DeviceInfo().ofClass())
        let dataQuery = DataQueryBuilder()
        var response = [DeviceInfo]()
     
        Types.tryblock({ () -> Void in
            // synchronous backendless API call here
            response = dataStore?.find(dataQuery) as! [DeviceInfo]
            
            print("I am here") //works!
    
        },
                       catchblock: { (exception) -> Void in
                        // handle error from server here
                        print("Server reported an error")
        })    }

ooh I found it, I kind of answered my own question with my clue!

I had it running inside

DispatchQueue.global(qos: .background).async {
...
}

Take it out of that block and it works fine. (used to work fine in swift3, but doesn’t in swift 4/5)

Olha, a bit beyond Backendless support, but what would you advise - just take it out of the background thread as it is an async operation anyway?

Mike

This code also works fine for me:

func test() {
    DispatchQueue.global(qos: .background).async {
        let dataStore = self.backendless?.data.of(DeviceInfo().ofClass())
        dataStore?.find({ (array) -> () in
            let devicesArray = array as! [DeviceInfo]
            print("did I find anything!")   // never even gets here
            print("Result: \(devicesArray)")
        }, error: {
            (fault : Fault?) -> () in
            print("Server reported an error: \(fault)")
        })
    }
}

What version of iOS-SDK do you use?

Got it! - I was using an old version of backendless SDK (4.0b7) in my podfile. Updated to the new one and it now works in. Thanks, problem solved!

DispatchQueue.global(qos: .background).async {}

Hi Olha

Ha, this again!

This time I was trying to call the exact same code but within the NotificationService.swift extension (same file as per your docs about setting up push notifications)

All works except this again. Same project, it just doesn’t fire again. Added objcMembers to data file, up to date SDK

import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    
    var backendless = Backendless.sharedInstance()
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?
    
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        
       BackendlessPushHelper.sharedInstance().processMutableContent(request, withContentHandler: contentHandler)
       test() //exact same routine
        
    }

Hello mike,

I know it’s a little bit painful but have you tried to debug the NotificationServiceExtension? You won’t see the console logs if you’re not in the debugging mode (I assume you won’t see them while debugging either). What are you going to change in the push notification appearance?

Regards,
Olha

Hi, Yes I am collecting debug information in the NotificationServiceExtension, but it is no help. It just does not fire in the same place as yesterday

 //gets here   
 dataStore?.find({ (array) -> () in
                // never gets here

I am actually not trying to change the push notification appearance, but what I am trying to do is to send data back to a table I have in backendless which collects information about how many messages have been received. ie. each time a device gets a notification I get a row added to a table which effectively says a deviceID has received that push message. Therefore we get feedback on the exact number of devices which received the message. That is the theory.

Hello,

Extensions in Xcode are separated from the main target. Please initialize Backendless for your service before calling your method:

override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
    BackendlessPushHelper.shared.processMutableContent(request: request, contentHandler: contentHandler)
        
    Backendless.shared.hostUrl = SERVER_URL
    Backendless.shared.initApp(applicationId: APPLICATION_ID, apiKey: API_KEY)

    // call your method here
}

Regards,
Olha

Thanks Olha, confirmed that works.