How to downcast a groupsCollection array to a swift array?


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

BLGroup Class:



class BLGroup: NSObject {

 
 // Backendless Group Entity
 var name: String?
 var users: [BLUser] = [BLUser]()
 var created: NSDate?
 var updated: NSDate?
 var objectId: NSString?
 var ownerId: NSString?



}

When running the code I get the following error:

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

What is the correct way to downcast a groupsCollection array to a swift array?

With ‘groupsCollection’ I mean ‘BackendlessCollection’, should have asked it differently.

After trying some more I seem unable to cast any retrieved object to my custom backendless entity classes. Is there any example of how to do this in swift?

Maybe I’m overlooking things, but I can’t seem to find any documentation / examples for it?

Just to make things more complete, here is the code that calls the getUsersFromGroups method:

let query = BackendlessDataQuery()
 let queryOptions = QueryOptions()
 queryOptions.related = NSMutableArray(array: ["users"])
 query.queryOptions = queryOptions
 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)")
 })

I’ve also tried it like this (from the Advanced Search example):


 func getUsersFromGroups(groupsCollection:BackendlessCollection) {
 for group in groupsCollection.data as! [BLGroup] {
 print ("Group: ", group)
 }
 }

But that gives me also a fatal error (on line 4 of the example code above):

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

Hi, Barry,

Our iOS developer is already looking into this issue. He shall contact you here as soon as possible.
Regards,
Sergey

Hi Barry,

These blog posts demonstrate the best practice of data retrieving (see Swift code pages):
https://backendless.com/feature-16-data-retrieval-api-how-to-load-objects-from-an-mbaas-storage/
https://backendless.com/feature-17-data-paging-or-how-to-efficiently-load-large-data-sets-in-a-mobile-app/
https://backendless.com/feature-21-loading-related-data-objects-the-auto-load-approach/
https://backendless.com/feature-22-loading-related-data-objects-the-one-stepdynamic-approach/
https://backendless.com/feature-28-loading-related-data-objects-the-semi-lazy-approach/

Regards,
Slava

Yes, you could not cast groupsCollection.data (NSArray) to [BLGroup] (Swift Array).

But it can be done with assignment operator:

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

Hi Slava,

I modified my code to use the example (https://backendless.com/feature-16-data-retrieval-api-how-to-load-objects-from-an-mbaas-storage/) you posted.

However, that code doesn’t even compile:




        func getUsersFromGroups(groupsCollection:BackendlessCollection) {
            let currentPage = groupsCollection.getCurrentPage()
            //print ("Class: ",groupsCollection.type)
            
            print ("count: ",currentPage.count)
            
            for group in currentPage {
                //let group = group as! BLGroup
                print ("Group: \(group.name)")
                print ("Group: ", group)
            }

Error: Ambiguous use of ‘name’

Which makes sense as ‘group’ is not of class BLGroup and has no property called name.

Is there a demo project that contains a working swift example?

This also doesn’t work for me:


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

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

By the way: All testing is done with Xcode 7.1.1 which contains Swift 2.1


func getUsersFromGroups(groupsCollection:BackendlessCollection) {
let currentPage = groupsCollection.getCurrentPage()
print ("count: \(currentPage.count")

for group in currentPage as! [BLGroup] {
print ("Group: \(group.name)")
}

And you could download the working demo samples from the ‘Feature-a-Day’ blog posts:

Im going to try the demo.

The code you posted still gives me the same error (already tried that).

class BLGroup: NSObject {


// Backendless Group Entity
var name: String?
var users: [BLUser]?
var created: NSDate?
var updated: NSDate?
var objectId: NSString?
var ownerId: NSString?



}

Sorry, same error.

Will report back when I got the demo up & running.

You can try it with my application:

let APP_ID = "CF47722D-EB7B-A0D0-FFE3-1FADE3346100"

let SECRET_KEY = "43B43EF7-247A-ED56-FF2F-ECD43C6E9000"

See https://github.com/Backendless/BlogFeatureDay-iOS/blob/master/F52FetchingUsers/F52FetchingUsersSwift/ViewController.swift

as example of fetching users

I’ve got the demo up & running and it is working fine.

I think the problem is in the fact that I have a custom (to many) relation to the Group entity in the Users entity. Changing the array declaration to:

 var users: [BackendlessUser]?

also doesn’t work.

What do I want to achieve?

I have created a BLGroup entity which contains a one to many relation to Users (one group can contain lot’s of users).

I created a user property ‘groups’ which is a one to many relation to the BLGroup entity (one user can be in many groups).

Now I want to retrieve all users that are in the same group(s) as the userservice.currentUser

Test Code:


    func syncAllUsers() {
        let bl = appDelegate.backendless
        
        func getUsersFromGroups(groupsCollection:BackendlessCollection) {
            let currentPage = groupsCollection.getCurrentPage()
            print ("count: \(currentPage.count)")
                for group in currentPage as! [BLGroup] {
                    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()
    }

Am I doing something that I’m not supposed to? Should I do it in a different way?

You can not use whereClause for one-to-many relation - only for object properties and one-to-one relations. (Sorry, It is mistake! - see http://support.backendless.com/t/how-to-downcast-a-groupscollection-array-to-a-swift-array#comment-4624)

You could implement your use case, for example:

func getGroupsFromCurrentUser() {
print ("Current User: ", backendless.userService.currentUser)
// Create relation query for fetching the users relations
let query = BackendlessDataQuery()
// Where clause - find a a user with id bl.userService.currentUser.objectId
query.whereClause = "objectId = '\(backendless.userService.currentUser.objectId)'"
// Get BLUser object with all relations on depth 2 (its [BLGroup] with them [BLUser])
let queryOptions = QueryOptions()
queryOptions.relationsDepth = 2
query.queryOptions = queryOptions
let users = backendless.persistenceService.of(BLUser.ofClass())
users.find(
query,
response: { (var groupsCollection : BackendlessCollection!) -> () in
let groups = groupsCollection.getCurrentPage()
for group in grops as! [BLGroup] {
print ("Users: \(group.users)")
}
},
error: { (fault : Fault!) -> () in
print("Server reported an error (ASYNC): \(fault)")
})
}

Thanks a lot!

However there still is a problem:

Server reported an error (ASYNC): FAULT = ‘1009’ [Unable to retrieve data - unknown entity] <Unable to retrieve data - unknown entity>

This is caused I guess because BLUser does not exist. BLUser is a subclass of BackendlessUser.

However, when I change:

let users = backendless.persistenceService.of(BLUser.ofClass())

To:

let users = backendless.persistenceService.of(BackendlessUser.ofClass())

Then I get this error again:

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

Creating a subclass of BackendlessUser is not very good practice. I would try to avoid it by any means.