简体   繁体   中英

How to append struct into Array? Swift4

Function

import Foundation

struct Foods {
    var fid: Int
    var fname: String
    var hits: Int?
    var addr: String?
}

class Food {

    func getFoodsById(_ fid: Int) -> [Foods]? {
        var foods: Array<Foods>?
        let URL_GET_TEAMS:String = "http://jsm0803.iptime.org:81/html/sufoo/getFoodById.php"
        let requestURL = URL(string: URL_GET_TEAMS)

        let request = NSMutableURLRequest(url: requestURL!)

        request.httpMethod = "POST"
        //request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        let postParameters = "Fid=" + String(fid)
           // "name="+teamName!+"&member="+memberCount!;

        request.httpBody = postParameters.data(using: String.Encoding.utf8)


        let task = URLSession.shared.dataTask(with: request as URLRequest){data, response, error in

            if error != nil{
                print("error is \(error)")
                return;
            }
            let dataString = String(data: data!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue)) // 테스트용
            //print(dataString!)


            do{
                var itemJSON: Dictionary<String, Any>!
                itemJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? Dictionary


                let items:Array<Dictionary<String, Any>> = itemJSON["Food"] as! Array

                for i in 0 ..< items.count{
                    var food: Foods
                    let item = items[i]

                    let fid:Int = item["Fid"] as! Int
                    let fname: String = item["Fname"] as! String
                    let hits: Int? = item["Hits"] as? Int
                    let delegate_image:String? = item["Delegate_Image"]as? String

                    food = Foods(fid: fid, fname: fname, hits: hits, addr: delegate_image)

                    foods?.append(food)



                    print("fid ->", food.fid)
                    print("fname ->", food.fname)
                    if let f = food.hits {
                        print("hits ->", f)
                    }
                    else{
                        print("hits ->", food.hits as Any)
                    }
                    if let f = food.addr {
                        print("delegate_image -> ", f)
                    }
                    else {
                        print("delegate_image -> ", food.addr as Any)
                    }

                    print("==============")
                    print("")

                    print ("fid ==== ", foods?.first?.fid)
                    print ("fid ==== ", foods?.last?.fid)

                }
            }catch {
                print(error)
            }
        }
        task.resume()

        if let result = foods{
            for r in result{
                print ("r.fname")
                print (r.fname)
            }
        }
        print ("000000")
        return foods
    }

}

If I run this code in Xcode, I get the result below:

000000

fid -> 140

fname -> 밀 흑밀

hits -> nil

delegate_image -> ./pic_data/2309/20180423201954alj

==============

fid ==== nil
fid ==== nil

I want to return [var foods: Array?] value. But although I made some values of Foods struct and used append function of Array in order to add Foods value into Array, it didn't works. There is no value in Array, only nil.(fid ==== nil) Thus, it is useless to return that Array.

How can I get right results?

I need to get values like below:

fid ==== 140
fid ==== 140

Please help me to solve this problem. I think I used Optional wrongly.

Better make a model class to store data. For example:

class Food {
  var fid: Int
  var fname: String
  var hits: Int?
  var addr: String?
}

Then after getting result do something like this :

var foodArray = [Foods]()
for item in items {
   let food = Food()
   guard let food.fid = item["Fid"] as? Int else {return}
   foodArray.append(food)
}
print(foodArray)

And suggested by Francesco Deliro, use completion handler to return values when your for loop is done. In your case return statement is getting called before for loop ends.

Also don't do force unwrapping, try to use if let/ guard let .

You need to change your function implementation adding a completion handler, because your return is called before the for loop is ended:

func getFoodsById(_ fid: Int, completion: (([Foods]?, Error?) -> Void)?) {

    //your precedent code
    //then when you make the request call the completion

    let task = URLSession.shared.dataTask(with: request as URLRequest){data, response, error in

        guard error == nil else {
            completion?(nil, error)
            return
        }
        let dataString = String(data: data!, encoding: String.Encoding(rawValue: String.Encoding.utf8.rawValue)) // 테스트용
        //print(dataString!)


        do{
            var itemJSON: Dictionary<String, Any>!
            itemJSON = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? Dictionary


            let items:Array<Dictionary<String, Any>> = itemJSON["Food"] as! Array

            for i in 0 ..< items.count{
                var food: Foods
                let item = items[i]

                let fid:Int = item["Fid"] as! Int
                let fname: String = item["Fname"] as! String
                let hits: Int? = item["Hits"] as? Int
                let delegate_image:String? = item["Delegate_Image"]as? String

                food = Foods(fid: fid, fname: fname, hits: hits, addr: delegate_image)

                foods?.append(food)



                print("fid ->", food.fid)
                print("fname ->", food.fname)
                if let f = food.hits {
                    print("hits ->", f)
                }
                else{
                    print("hits ->", food.hits as Any)
                }
                if let f = food.addr {
                    print("delegate_image -> ", f)
                }
                else {
                    print("delegate_image -> ", food.addr as Any)
                }

                print("==============")
                print("")

                print ("fid ==== ", foods?.first?.fid)
                print ("fid ==== ", foods?.last?.fid)

            }
            completion?(foods, nil)
        }catch {
            print(error)
            completion?(nil, error)
        }
    }
    task.resume()
}

And you can use it in this way:

//where you have to make the call
self.getFoodsById(yourId) { (foodsArray, error) in
    //here you can manage your foods array
}

Main problem is you did not initiate your foods array.

//func getFoodsById(_ fid: Int) -> [Foods]? {
func getFoodsById(_ fid: Int) -> [Foods] {
    //var foods: Array<Foods>?
    var foods = [Foods]() // or  var foods: [Foods] = []

You can initiate your array here and return empty list as a result if there is no food for the ID.

And rename your Foods struct with Food and Food class with something like FoodOperations. This would make more sense.

Read this for swift guides.

struct Food {
    ...
}
class FoodOperations {
    ...
}

if let error = error {
   print("error is \(error)")
   return;
}

print ("fid ==== ", foods.first?.fid ?? 0)

Declare Struct

struct AlertModel { var alert:String var title:String }

Create Variable

var alertData = AlertModel

Append data

let alert = AlertModel(alert: "Waring", title: "Over Load") alertData.append(alert)
print(alertData)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM