0

I have a 3D array that is built via a an enumerated for loop that performs a background query of local SQL Lite table. 99% of the time everything is in order. 1% of the time things get a bit out of sequence.

As the code to perform the background task is contained within a closer that has a completion handler I'm not sure why the sequence gets funny. Below is how the structs and arrays are formed.

I was thinking of sorting the array but cant get the syntax and not sure if this is the best approach? it feels like a work around.

struct CollectionStruct {
    var name : String
    var description : String
    var title : String
    var image : PFFile
    var id: String
}

var packArray : [CollectionStruct] = []
var partArray : [CollectionStruct] = []
var multiPartArray : [[CollectionStruct]] = []
var tempPartArray : [[CollectionStruct]] = []

override func viewDidLoad() {
    super.viewDidLoad()

    // Built the self.packArray here in simalr fashion to below.
    // Always in correct order as the query to build it is sorted


    // Now build the partArray for each packArray

    // access with
    // self.multiPartArray[0][0].name

    for (index, item) in  self.packArray.enumerated() {

        print(index, item)

        // is it the index that is out of sequence?
        self.packId = self.packArray[index].id

        BuildArray.buildArrayFromQuery(queryForCollection: "Part", selectedPackID: self.packId, delegateSender: "DownloadPart", completeBlock: { (result) in

            if result.isEmpty == false {

                self.partArray = result
                // this is how i was appending the result.  But it will occasionaly append the results in the wrong order.
                // self.packArray[1], self.packArray[0].  Not sure if its because of the index from the enumeration or what??

                // self.multiPartArray.append(self.partArray)

                // this is where i was thinking of sorting the array ( or outside for loop ) this will do for not to test
                // set it to a temp so it can be sorted...
                self.tempPartArray.append(self.partArray)

                // now sort it.. dont know wtf to do here cant see anything online
                self.multiPartArray = self.tempPartArray.sorted(by: { ([CollectionStruct], [CollectionStruct]) -> Bool in
                    <#code#>
                })

            }
        })
    }
}

I can not figure out the syntax for how to sort this. In another location i have used the below code to sort a smaller struct array:

self.packArray = result.sorted {
    $0.name < $1.name
}

---- EDIT ----

The prompted code for the .sorted function is as shown below, where there is [CollectionStruct], [CollectionStruct] However The properties from my Struct ( .name ect ) are not available in the sort.

self.multiPartArray = self.tempPartArray.sorted(by: { ([CollectionStruct], [CollectionStruct]) -> Bool in
     <#code#>
})

The typical $0 < $1 ect is not available either as i can not apply binary operators to 2 Structs?? Ideally i can sort by the .name as this is a sequential identifier. So sort by

self.multiPartArray[0][0].name < self.multiPartArray[0][1].name < .... so on

This is a sample output of the data, when it is out of sequence, you can see that pk010 is coming after pk020, everything else is in sequence.

[[Proj.CollectionStruct(name: "pk000-01", description: "This is an intro session. ", title: "Session 1", image: <PFFile: 0x7b91dff0>, id: "JKE5K4xOQA"), Proj.CollectionStruct(name: "pk000-02", description: "This is a lot of text.", title: "Session 2", image: <PFFile: 0x7b892a30>, id: "ft4o3EWyxX"), Proj.CollectionStruct(name: "pk000-03", description: "This is session 3", title: "Session 3", image: <PFFile: 0x7a6fa5f0>, id: "jebz0c8Bq1"), Proj.CollectionStruct(name: "pk000-04", description: "This is a test", title: "Session 4", image: <PFFile: 0x7b88e390>, id: "E2rGHJMcR7"), Proj.CollectionStruct(name: "pk000-05", description: "This is a set", title: "Session 5", image: <PFFile: 0x7b892320>, id: "dkRAUEbdUb"), Proj.CollectionStruct(name: "pk000-06", description: "Test", title: "Session 6", image: <PFFile: 0x7a6f68a0>, id: "ODTJd3gIml")],
 [Proj.CollectionStruct(name: "pk020-01", description: "This is an intro session", title: "Session 1", image: <PFFile: 0x7a6f7600>, id: "6uG2cJGxrZ"), Proj.CollectionStruct(name: "pk020-02", description: "Session 2", title: "Session 2", image: <PFFile: 0x7b878d60>, id: "6T6r8e8dS3"), Proj.CollectionStruct(name: "pk020-03", description: "Session 3", title: "Session 3", image: <PFFile: 0x7a7a0ff0>, id: "2hDSALAG0a"), Proj.CollectionStruct(name: "pk020-04", description: "Session 4", title: "Session 4", image: <PFFile: 0x7b910bd0>, id: "vd0eBYb3gr"), Proj.CollectionStruct(name: "pk020-05", description: "Session 5", title: "Session 5", image: <PFFile: 0x7b88f790>, id: "MS8ece8dr8"), Proj.CollectionStruct(name: "pk020-06", description: "Session 6", title: "Session 6", image: <PFFile: 0x7a7765c0>, id: "aDfmH8bFKU"), Proj.CollectionStruct(name: "pk020-07", description: "Session 7", title: "Session 7", image: <PFFile: 0x7b9eaf50>, id: "obfW0pZsBH"), Proj.CollectionStruct(name: "pk020-08", description: "Session 8", title: "Session 8", image: <PFFile: 0x7a783c20>, id: "cVmEefiirT")],
 [Proj.CollectionStruct(name: "pk010-01", description: "This is an intro session", title: "Session 1", image: <PFFile: 0x7a6f9b20>, id: "BPtmDXvzDF"), Proj.CollectionStruct(name: "pk010-02", description: "Session 2", title: "Session 2", image: <PFFile: 0x7a79ac00>, id: "B3MAHoFEYs"), Proj.CollectionStruct(name: "pk010-03", description: "Session 3", title: "Session 3", image: <PFFile: 0x7a627e40>, id: "Yg6TxTuyHi"), Proj.CollectionStruct(name: "pk010-04", description: "Session 4", title: "Session 4", image: <PFFile: 0x7a627f90>, id: "XTRUoKVH9P"), Proj.CollectionStruct(name: "pk010-05", description: "Session 5", title: "Session 5", image: <PFFile: 0x7a627b80>, id: "eO9xS05qsW"), Proj.CollectionStruct(name: "pk010-06", description: "Session 6", title: "Session 6", image: <PFFile: 0x7b879bd0>, id: "ePZdmFnnoQ"), Proj.CollectionStruct(name: "pk010-07", description: "Session 7", title: "Session 7", image: <PFFile: 0x7be58c50>, id: "BO6HGa7w1R"), Proj.CollectionStruct(name: "pk010-08", description: "Session 8", title: "Session 8", image: <PFFile: 0x7a69bd20>, id: "dwIxpmD2y8")],
 [Proj.CollectionStruct(name: "pk030-01", description: "Session 3", title: "Session 3", image: <PFFile: 0x7b87da60>, id: "lU1rm5cnbb")]]

----- EDIT ----

I still haven't been able to sort this but I've been playing with at least catching the error, its not too graceful as its in another enumerated loop but its the best my brain has at the moment.

// add a group for the for enumeration check
let insideGroup = DispatchGroup()

for (index, item) in self.tempPartArray.enumerated() {
    insideGroup.enter()
    if index >= 1 {
        // if the currentItem.name > the previousItem.name
        if item[0].name > self.tempPartArray[index - 1][0].name {
            print("The array is in sequence")
            insideGroup.leave()

        } else {
            print("the array is out of sequence")

            // exit gracefully
        }
    }
}
// the enumeration has finished you can set the variables
insideGroup.notify(queue: .main) {
    self.multiPartArray = self.tempPartArray
}

----- EDIT ----

Even re-writing the queries to be synchronous tasks still returns data out of sequence as one query might take longer than another.

I think what i need to do here is make the query part of an Operation with a axConcurrentOperationCount = 1

That should force the results into sequence.

Id still like to know how to sort this type of array though....

WanderingScouse
  • 281
  • 1
  • 3
  • 16

1 Answers1

1

Assuming your buildArrayFromQuery isn't asynchronous, I simplified your loops in a way that should prevent any weirdness:

func findAllItems() {

    var allFoundItems: [[CollectionStruct]] = []
    for item in packArray {

        let packId = item.id

        BuildArray.buildArrayFromQuery(queryForCollection: "Part", selectedPackID: packId, delegateSender: "DownloadPart", completeBlock: { (result) in
            if result.isEmpty == false {
                allFoundItems.append(result)
            }
        })
    }
    multiPartArray = allFoundItems
}

If buildArrayFromQuery is asynchronous, you should re-evaluate how you're doing this generally and make something that asynchronously simply gets all the arrays and calls a closure with them sorted. But if you need a sort, this should work:

self.multiPartArray = tempPartArray.sorted  {
    // $0 is the left item, $1 is the right item.
    // However you're sorting your items, just put the logic in here.
    return $0 < $1
 }
GetSwifty
  • 7,568
  • 1
  • 29
  • 46
  • Thanks, the query does get the objects async. I was naively under the impression that because it was done through completion block it would come back in order. Like you said i can get all the objects / arrays and then process it how i need. I tried using dispatchGroup enter/leave and completion in the for loop to force it to sync but it does slow it down a bit and this could probably result in locking the thread when the collection gets bigger. With the sort, Xcode is promoting me to use .sorted(by: { [..], [..] } -> which i cant figure out. – WanderingScouse Feb 25 '17 at 00:06
  • The sorted by it's giving you is the just the longhand version of what's in my answer. If the method is Async that's probably why it sometimes ends up out of order. You'll probably need to either write a new method that queries for everything you need simultaneously or just wait and sort it after. – GetSwifty Feb 27 '17 at 16:37