How to downcast a groupsCollection array to a swift array?

Vyacheslav,

You say: ‘You can not use whereClause for one-to-many relation - only for object properties and one-to-one relations.’

However, this works fine for me:


func getGroupsFromCurrentUser() {
            print ("Current User: ",bl.userService.currentUser)
            
            // Create relation query for fetching the users relations
            let query = BackendlessDataQuery()
            let queryOptions = QueryOptions()
            queryOptions.related = NSMutableArray(array: ["users"])
            query.queryOptions = queryOptions
            
            // Where clause - find all groups that contain a user with id bl.userService.currentUser.objectId
            query.whereClause = "users.objectId = '\(bl.userService.currentUser.objectId)'"
            
            let groupCollection = backendless.persistenceService.of(BLGroup.ofClass())
            
            groupCollection.find(query, response: {(
                groups : BackendlessCollection!) -> () in
                print("Groups have been fetched  (ASYNC): \(groups)")
                getUsersFromGroups(groups)
                },
                error: { (fault : Fault!) -> () in
                    print("Server reported an error (ASYNC): \(fault)")
            })


        }

Will there be any unwanted side-effects of doing it this way? Or can I use this safely?

Im really not getting it:

 
 func getUsersFromGroups(groupsCollection:BackendlessCollection) {
 let currentPage = groupsCollection.getCurrentPage()
 print ("count: \(currentPage.count)")
 for group in currentPage {
 print ("Group: \(group)")
 }
 }
 
 func getGroupsFromCurrentUser() {
 print ("Current User: ",bl.userService.currentUser)
 
 // Create relation query for fetching the users relations
 let query = BackendlessDataQuery()
 let queryOptions = QueryOptions()
 queryOptions.related = NSMutableArray(array: ["users"])
 query.queryOptions = queryOptions
 
 // Where clause - find all groups that contain a user with id bl.userService.currentUser.objectId
 query.whereClause = "users.objectId = '\(bl.userService.currentUser.objectId)'"
 
 let groupCollection = backendless.persistenceService.of(BLGroup.ofClass())
 
 groupCollection.find(query, response: {(
 groups : BackendlessCollection!) -> () in
 print("Groups have been fetched (ASYNC): \(groups)")
 getUsersFromGroups(groups)
 },
 error: { (fault : Fault!) -> () in
 print("Server reported an error (ASYNC): \(fault)")
 })

 }
 
 getGroupsFromCurrentUser()

Log Output:

Groups have been fetched (ASYNC): <BackendlessCollection> -> type: (null), offset: 0, pageSize: 100, totalObjects: 1, data: ( { “___class” = BLGroup; “__meta” = “{“relationRemovalIds”:{},“selectedProperties”:[“created”,“name”,”___class",“ownerId”,“updated”,“objectId”,“users”],“relatedObjects”:{“users”:[“2FFCE40C-3095-3237-FF0F-C739D28EC900”,“E38DC051-82C5-1F30-FF3D-77C3D1103500”]}}"; created = “2015-11-23 14:37:04 +0000”; name = “TestGroup”; objectId = “CB08C1AF-EB24-D28B-FF53-5DB53C923D00”; ownerId = “<null>”; updated = “<null>”; users = ( “<BackendlessUser> email:‘xxxxxxxx’, password:’<null>’, name:’<null>’, userId:‘2FFCE40C-3095-3237-FF0F-C739D28EC900’, userToken:’(null)’, objectId:‘2FFCE40C-3095-3237-FF0F-C739D28EC900’, properties:{\n “___class” = Users;\n “__meta” = “{\“relationRemovalIds\”:{},\“selectedProperties\”:[\“password\”,\“firstname\”,\“initials\”,\“created\”,\“middlename\”,\“groups\”,\“ownerId\”,\“updated\”,\“objectId\”,\“email\”,\“lastname\”],\“relatedObjects\”:{}}”;\n created = “2015-11-16 13:52:56 +0000”;\n email = “xxxxx”;\n firstname = xxxx;\n groups = “<null>”;\n initials = xxx;\n lastname = xxxxx;\n middlename = “<null>”;\n name = “<null>”;\n objectId = “2FFCE40C-3095-3237-FF0F-C739D28EC900”;\n ownerId = “<null>”;\n password = “<null>”;\n updated = “2015-11-20 14:07:11 +0000”;\n userId = “2FFCE40C-3095-3237-FF0F-C739D28EC900”;\n userToken = “<null>”;\n}”, “<BackendlessUser> email:‘xxxxx’, password:’<null>’, name:’<null>’, userId:‘E38DC051-82C5-1F30-FF3D-77C3D1103500’, userToken:’(null)’, objectId:‘E38DC051-82C5-1F30-FF3D-77C3D1103500’, properties:{\n “___class” = Users;\n “__meta” = “{\“relationRemovalIds\”:{},\“selectedProperties\”:[\“password\”,\“firstname\”,\“initials\”,\“created\”,\“middlename\”,\“groups\”,\“ownerId\”,\“updated\”,\“objectId\”,\“email\”,\“lastname\”],\“relatedObjects\”:{}}”;\n created = “2015-11-20 14:05:13 +0000”;\n email = “xxxxx”;\n firstname = xxxx;\n groups = “<null>”;\n initials = D;\n lastname = xxxx;\n middlename = “<null>”;\n name = “<null>”;\n objectId = “E38DC051-82C5-1F30-FF3D-77C3D1103500”;\n ownerId = “<null>”;\n password = “<null>”;\n updated = “2015-11-20 14:05:49 +0000”;\n userId = “E38DC051-82C5-1F30-FF3D-77C3D1103500”;\n userToken = “<null>”;\n}” ); }), query: <BackendlessDataQuery> -> properties: (null), whereClause: users.objectId = ‘2FFCE40C-3095-3237-FF0F-C739D28EC900’, queryOptions: <QueryOptions> -> { offset = 0; pageSize = 100; related = ( users );}

count: 1
Group: { “___class” = BLGroup; “__meta” = “{“relationRemovalIds”:{},“selectedProperties”:[“created”,“name”,”___class",“ownerId”,“updated”,“objectId”,“users”],“relatedObjects”:{“users”:[“2FFCE40C-3095-3237-FF0F-C739D28EC900”,“E38DC051-82C5-1F30-FF3D-77C3D1103500”]}}"; created = “2015-11-23 14:37:04 +0000”; name = “TestGroup”; objectId = “CB08C1AF-EB24-D28B-FF53-5DB53C923D00”; ownerId = “<null>”; updated = “<null>”; users = ( “<BackendlessUser> email:‘xxxxxxxx’, password:’<null>’, name:’<null>’, userId:‘2FFCE40C-3095-3237-FF0F-C739D28EC900’, userToken:’(null)’, objectId:‘2FFCE40C-3095-3237-FF0F-C739D28EC900’, properties:{\n “___class” = Users;\n “__meta” = “{\“relationRemovalIds\”:{},\“selectedProperties\”:[\“password\”,\“firstname\”,\“initials\”,\“created\”,\“middlename\”,\“groups\”,\“ownerId\”,\“updated\”,\“objectId\”,\“email\”,\“lastname\”],\“relatedObjects\”:{}}”;\n created = “2015-11-16 13:52:56 +0000”;\n email = “xxxxx”;\n firstname = xxxxx\n groups = “<null>”;\n initials = xxx;\n lastname = xxxxx;\n middlename = “<null>”;\n name = “<null>”;\n objectId = “2FFCE40C-3095-3237-FF0F-C739D28EC900”;\n ownerId = “<null>”;\n password = “<null>”;\n updated = “2015-11-20 14:07:11 +0000”;\n userId = “2FFCE40C-3095-3237-FF0F-C739D28EC900”;\n userToken = “<null>”;\n}”, “<BackendlessUser> email:‘xxxxxxxx’, password:’<null>’, name:’<null>’, userId:‘E38DC051-82C5-1F30-FF3D-77C3D1103500’, userToken:’(null)’, objectId:‘E38DC051-82C5-1F30-FF3D-77C3D1103500’, properties:{\n “___class” = Users;\n “__meta” = “{\“relationRemovalIds\”:{},\“selectedProperties\”:[\“password\”,\“firstname\”,\“initials\”,\“created\”,\“middlename\”,\“groups\”,\“ownerId\”,\“updated\”,\“objectId\”,\“email\”,\“lastname\”],\“relatedObjects\”:{}}”;\n created = “2015-11-20 14:05:13 +0000”;\n email = “xxxxx”;\n firstname = xxxx;\n groups = “<null>”;\n initials = D;\n lastname = xxxxx;\n middlename = “<null>”;\n name = “<null>”;\n objectId = “E38DC051-82C5-1F30-FF3D-77C3D1103500”;\n ownerId = “<null>”;\n password = “<null>”;\n updated = “2015-11-20 14:05:49 +0000”;\n userId = “E38DC051-82C5-1F30-FF3D-77C3D1103500”;\n userToken = “<null>”;\n}” );}
So that looks fine to me, however as soon as I try this:

func getUsersFromGroups(groupsCollection:BackendlessCollection) {
 let currentPage = groupsCollection.getCurrentPage()
 print ("count: \(currentPage.count)")
 for group in currentPage as! [BLGroup] {
 print ("Group: \(group)")
 }
 }

Then it crashes:

fatal error: NSArray element failed to match the Swift Array Element type

What should I do/try next?

Hi Barry,

For successful casting from NSArray (not typified) to Swift Array (typified) you should create the variable or constant as Swift Array, and then it can be assigned with NSArray, for example:

 
 
 
 
 
 
 
 
 
 
 func getUsersFromBackendlessCollection(bc:BackendlessCollection) { 
 
 let groups = bc.getCurrentPage() as! [BLGroup] 
 
 for group in groups { 
 
 for user in group.users! { 
 
 print ("\(user.email)") 
 
 } 
 
 } 
 
 } 



or

 
 
 
 
 
 
 
 
 
 
 func fetchingGroups() -> [BLGroup] { 
 
 
 
 var groups = [] // [AnyObject]() 
 
 
 
 Types.tryblock({ () -> Void in 
 
 
 
 let query = BackendlessDataQuery() 
 
 let queryOptions = QueryOptions() 
 
 queryOptions.relationsDepth = 1 
 
 query.queryOptions = queryOptions 
 
 
 
 let dataStore = self.backendless.data.of(BLGroup.ofClass()) 
 
 groups = dataStore.find().getCurrentPage() 
 
 }, 
 
 
 
 catchblock: { (exception) -> Void in 
 
 print("Server reported an error: \(exception as! Fault)") 
 
 } 
 
 ) 
 
 
 
 return groups as! [BLGroup] 
 
 } 
 
 



I have implemented the sample with your usecase - it works for me, you can try it:
https://drive.google.com/file/d/0B3yyaWhA4ib0OS01ci1OSTVfc2M/view?usp=sharing

You are right - you can use query.whereClause for one-to-many relation, and besides on the depth more then one. So, for fetching all users having part in the groups with currentUser you could find them in Users table using

 query.whereClause = "groups.users.objectId = '\(backendless.userService.currentUser.objectId)'"

for example:

 func getCommonGroupsUsersForCurrentUser() {
 print ("\nCurrent User: \(backendless.userService.currentUser)\n")
 // Create relation query for fetching the users relations
 let query = BackendlessDataQuery()
 // Where clause - find the all users having part in the groups with currentUser
 query.whereClause = "groups.users.objectId = '\(backendless.userService.currentUser.objectId)'"
 let dataStore = backendless.data.of(BackendlessUser.ofClass())
 dataStore.find(
 query,
 response: {(bc : BackendlessCollection!) -> () in
 let users = bc.getCurrentPage() as! [BackendlessUser]
 for user in users {
 print ("\(user.email)")
 }
 },
 error: { (fault : Fault!) -> () in
 print("Server reported an error (ASYNC): \(fault)")
 })
 }

Thanks a lot for your great support!

Your func getCommonGroupsUsersForCurrentUser() method does work nicely and is exactly what I needed!

Guys,

Im having the same problemen again over here.

I created a BLDevice Class:

class BLDevice: NSObject {
 
 // Backendless Device Entity
 var name: String?
 var user: BackendlessUser?
 var created: NSDate?
 var updated: NSDate?
 var objectId: NSString?
 var ownerId: NSString?
 
 var pdid: String?
 var deviceOS: String?
 var deviceOSVersion: String?
 var lastConnected: NSDate?
 var appVersion: String?
}

Now I want to query for a device (by matching pdid):

 let query = BackendlessDataQuery()
 query.whereClause = "pdid = '\(pdid)'"
 
 let dataStore = backendless.data.of(BLDevice.ofClass())
 
 dataStore.find(
 query,
 response: {(bc : BackendlessCollection!) -> () in
 let devices = bc.getCurrentPage() as! [BLDevice]
 let device = devices.first
 print ("Device found! ",device)
 },
 error: { (fault : Fault!) -> () in
 print("Server reported an error (ASYNC): \(fault)")
 })

Getting this error: fatal error: NSArray element failed to match the Swift Array Element type

It looks like whenever I create a class with a relation to the users table -> things don’t work.

Hi,

Try this:

let query = BackendlessDataQuery()
query.whereClause = "pdid = '\(pdid)'"

let dataStore = backendless.data.of(BLDevice.ofClass())
var devices = [] // [AnyObject]()


dataStore.find(
query,
response: {(bc : BackendlessCollection!) -> () in
devices = bc.getCurrentPage() as! [BLDevice]
let device = devices.first
print ("Device found! ",device)
},
error: { (fault : Fault!) -> () in
print("Server reported an error (ASYNC): \(fault)")
})

Thanks!

Done it like this:

let devices : [AnyObject] = bc.getCurrentPage() as! [BLDevice]

Works!

Ok, now I want to do something with the retrieved device, but again: doesn’t work:

dataStore.find( 
 query, 
 response: {(bc : BackendlessCollection!) -> () in 
 let devices : [AnyObject] = bc.getCurrentPage() as! [BLDevice] 
 if devices.count > 0 { 
 print ("Device found, update it! ",devices.first) 
 let device = devices.first as! BLDevice 
 device.lastConnected = NSDate() 
 } else { 
 print ("Device not found, create it!") 
 createDevice() 
 } 
 }, 
 error: { (fault : Fault!) -> () in 
 print("Server reported an error (ASYNC): \(fault)") 
 }) 

This crashes on:

let device = devices.first as! BLDevice 

With error:

Could not cast value of type ‘__NSDictionaryM’ (0x4530380) to ‘Pro_Project.BLDevice’ (0x3fe708).

Im I doing something totally wrong?

What name did you use for your project/target? You should use a name without punctuation symbols, for example - “ProProject”.

It has a space in the name, which results in an underscore (Pro_Project). Is that causing the problems I have?

Yes, in swift internal class name has the form <target name>.<class name>, at that the all punctuation symbols are changed to “_” .

Ok, I refactored the project and target name, but still the same issue:

Could not cast value of type ‘__NSDictionaryM’ (0x4537380) to ‘ProProject.BLDevice’ (0x408708).

It works now! I also had to rename the Bundle name in the info.plist.

Thanks again for you amazing support!

Sorry to bother you guys again, but Im facing the same error today:

‘fatal error: NSArray element failed to match the Swift Array Element type’

Im getting this when trying to loop trough an array of BackendlessUser objects:

for user in group.users {
 print ("Create group relations for user \(user.email) with id: \(user.objectId)")
 }

group class:

class BLGroup: NSObject {
 
 // Backendless Group Entity
 var name: String?
 var users: [BackendlessUser] = []
 var created: NSDate?
 var updated: NSDate?
 var objectId: String?
 var ownerId: String?
}

I could not reproduce this issue. The following sample method works fine for me:

    func getGroupsForCurrentUser() {
        
        print ("\nCurrent User: \(backendless.userService.currentUser)\n")
        
        // Create relation query for fetching the users relations
        let query = BackendlessDataQuery()
        query.whereClause = "users.objectId = '\(backendless.userService.currentUser.objectId)'"


        let queryOptions = QueryOptions()
        queryOptions.relationsDepth = 1
        query.queryOptions = queryOptions


        let dataStore = backendless.data.of(BLGroup.ofClass())
        dataStore.find(
            query,
            response: {(bc : BackendlessCollection!) -> () in
                let groups : [BLGroup] = bc.getCurrentPage() as! [BLGroup]
                let group = groups.first
                print ("\(group!.name)")


                for group in groups {
                    print ("\(group)")
                    for user in group.users {
                        print ("Create group relations for user \(user.email) with id: \(user.objectId)")
                    }
                }


            },
            error: { (fault : Fault!) -> () in
                print("Server reported an error (ASYNC): \(fault)")
        })
    }

Try it - or give me your one (I would like to see whole method which crashes).

Yes, you’re using relation fetching, then it works.

But when you enable autoload and just fetch the users without the relations then it doesn’t work.

I encountered a similar problem with autoloading yesterday: http://support.backendless.com/t/setstayloggedin-ios-sdk-causes-crash

For now I’ve worked around this problem by disabling autoloading, but it would be great if you guys could look into this and fix it?