-4

Fatal Error out of range this is the log file

Alamofire URL request is within a loop the breaking point the system the counter is already 44 not the first index after getting the first value of the array.

I tried printing the array outside of the loop but it just give me a null array printing on log is just []

let url = "http://localhost:8080/iostest/selectstudents.php"
    let parameters: Parameters=[
        "StatusCodeID":"2",
        "subjectCode":"ENG 099",
        "section":"BSIT 2-2BSIT-01"
    ]
    Alamofire.request(url, method: .post, parameters: parameters).responseJSON{
        response in
        let json = response.data

        if let result = response.result.value {

            //converting it as NSDictionary
            let jsonData = result as! NSDictionary
            //displaying the message in label
            let x = jsonData.value(forKey: "Students") as! NSArray

            for dict in x {
                let dictone = dict as! NSDictionary

                ArrayStudentNumber.append(dictone["StudentNumber"]  as! String)
                ArraySection.append(dictone["Section"] as! String)
                ArraySemester.append(dictone["Semester"] as! String)
                ArraySubjectCode.append(dictone["SubjectCode"] as! String)
                ArraySchoolYear.append(dictone["SchoolYear"] as! String)
            }


        }

        let arraycount = ArrayStudentNumber.count
        var counter = 0
        while counter < arraycount{
        print(counter)
        var currentindex = counter
        print (ArrayStudentNumber[counter])
        let url2 = "http://localhost:8080/iostest/selectstudentsinfo.php"
        var parameters2: Parameters=["studentNumber" : ArrayStudentNumber[currentindex]]

        Alamofire.request(url2, method: .post, parameters: parameters2).responseJSON{
            response in
            let json = response.data
            if let result = response.result.value {
                print (response)
                //converting it as NSDictionary
                let jsonData = result as! NSDictionary
                //displaying the message in label
                let x = jsonData.value(forKey: "StudentsInfo") as! NSArray
                for dict in x {
                    let dictone = dict as! NSDictionary

                    ArrayFirstname.append(dictone["Firstname"]  as! String)
                    ArrayLastname.append(dictone["Lastname"]  as! String)
                    ArrayMiddlename.append(dictone["Middlename"]  as! String)
                    ArrayCollege.append(dictone["College"]  as! String)
                    ArrayCourse.append(dictone["Course"]  as! String)




                }

            }
        }

            counter += 1
    }

        var loopcounter = 0
        let thisarraycount = ArrayFirstname.count
        while loopcounter < thisarraycount{
            var insertstatemanet: OpaquePointer? = nil
            var insertsql = "insert into tableStudentInfo(StudentNumber,Firstname,Lastname,Middlename,College,Course,SubjectCode,Section,Semester,Schoolyear) values ('\(ArrayStudentNumber[loopcounter])','\(ArrayFirstname[loopcounter])','\(ArrayLastname[loopcounter])','\(ArrayMiddlename[loopcounter])','\(ArrayCollege[loopcounter])','\(ArrayCourse[loopcounter])','\(ArraySubjectCode[loopcounter])','\(ArraySection[loopcounter])','\(ArraySemester[loopcounter])','\(ArraySchoolYear[loopcounter])';"


            //isolate sql query and validate statements
            sqlite3_prepare_v2(db, insertsql, -1, &insertstatemanet, nil)
            //
            if sqlite3_step(insertstatemanet) == SQLITE_DONE{
                print("Inserted", "\(ArrayStudentNumber[counter])")
            }
            sqlite3_finalize(insertstatemanet)
        }
        loopcounter = loopcounter + 1


    }



}

1 Answers1

0

What I meant with the bad indented, it's that you don't it's hard to read the differents scopes, the tabs are weirdly done.

What's wrong with your code:

Here is the main logic your are doing:

//0
Alamofire.request(url, method: .post, parameters: parameters).responseJSON { response in
    if let result = response.result.value { //1
        //Populate arrays
    }

    whileLoop { //2
        Alamofire.request(url2, method: .post, parameters: parameters2).responseJSON { 
            if let result = response.result.value { //2.n
                //Populate arrays
            }
        }
    }
    whileLoop { //3
        //Populate SQL according to populated arrays
    }
}
//4

The first big issue is that you are missing the fact that your Alamofire Request is async. It means, that I you add print where I put //number, the print in the console might not be the one you expect. Currently, it should be: "0, 4, 1, 2, 3, 2.3, 2.5, 2.2, 2.1, 2.4 etc.", and not "0, 1, 2, 2.1, 2.2..., 3, 4". It's even worse, because 2.n might not even be in the order. So clearly, when you are doing the 3rd action (while loop for SQL), you don't have your values.

The Asynchrone concept is an import one that you need to understand and master, because it's really basic and common.

See: Returning data from async call in Swift function
Using a value from Alamofire request outside the function etc.

I guess that's why you put the while Loop for the second batch (//2) of request inside the first one.

What you need to do is use a DispatchGroup, with enter(), leave(), notify():

Swift / How to use dispatch_group with multiple called web service?
How do I use DispatchGroup / GCD to execute functions sequentially in swift?
Waiting until the task finishes
Swift closure async order of execution
Wait until swift for loop with asynchronous network requests finishes executing
etc.

With the key words and links to look for, you should be able to have a working solution.

Now, in Swift 3+, avoid using NSStuff, like NSDictionary, NSArray, prefers the Swift version when available.

Example:

let jsonData = result as! NSDictionary

=>

let jsonData = result as! [String: Any]

Avoid using value(forKey:), its results might surprise you some day. KVC needs to be understood for that. Each thing in its due time, but as you seem to begin, avoid using it. Prefers object(forKey:), or a direct subscript: myDict["myKey"]

Avoid force cast (using the !). Why? That's telling the compiler: Don't worry, I know what I'm doing (which often is not the case, let's be clear). And if I'm wrong, just crash. So that's quite a gamble to make crash your app because in one case you couldn't cast it, or made the wrong cast, no? Prefer if let, guard let, etc.

Finally:

ArrayStudentNumber.append(dictone["StudentNumber"])
ArraySection.append(dictone["Section"])
ArraySemester.append(dictone["Semester"])
ArraySubjectCode.append(dictone["SubjectCode"])
ArraySchoolYear.append(dictone["SchoolYear"])

No. Just don't. Don't use multiple arrays for that. Just use one. Why? What happens if you want to remove the first one, you'll remove the fist one on each of theses arrays? What if you want to reorder one (because you now find it better that the students are sorted by id/student number and not their name)? You'll sort the 4 other arrays too? These info have meaning all together only.

Use an array of dictionary, a array of custom object to hold their values, etc.

Also, since you'll learn about the asynchronous thing, you'll see that in you other for loop (since you do the same) ArrayFirstname.first might not be for ArrayStudentNumber.first (remember the 2.1, 2.2 order I told you about?)

Larme
  • 24,190
  • 6
  • 51
  • 81