Y Kim
Y Kim

Reputation: 1

Type 'NSFastEnumerationIterator.Element' has no subscript members

I'm having troubles with this error.

Would you tell me how to fix this code to workout?

Any help will be appreciated.

//This is JSON data.

{  
   "boxOfficeResult":{  
      "boxofficeType":"일별 박스오피스",
      "showRange":"20161020~20161020",
      "dailyBoxOfficeList":[  
         {  
            "rnum":"1",
            "rank":"1",
            "rankInten":"0",
            "rankOldAndNew":"OLD",
            "movieCd":"20153444",
            "movieNm":"럭키",
            "openDt":"2016-10-13",
            "salesAmt":"1452501900",
            "salesShare":"60.2",
            "salesInten":"-85908900",
            "salesChange":"-10",
            "salesAcc":"23329189948",
            "audiCnt":"193801",
            "audiInten":"-11203",
            "audiChange":"-10",
            "audiAcc":"2879481",
            "scrnCnt":"968",
            "showCnt":"4961"
         }, ...

//This is code.

var list = Array<MovieVO>()

override func viewDidLoad() {

    let apiURI = NSURL(string: "http://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=a7497a5e700fdff2f3fd468b604d9d18&targetDt=20161020")

    let apidata : NSData? = NSData(contentsOf: apiURI! as URL)

    NSLog("result = %@", NSString(data: apidata! as Data, encoding: String.Encoding.utf8.rawValue)!)


    do {
        let apiDictionary = try JSONSerialization.jsonObject(with: apidata! as Data, options: []) as! NSDictionary

        let boxOfficeResult = apiDictionary["boxOfficeResult"] as! NSDictionary
        let dailyBoxOfficeList = boxOfficeResult["dailyBoxOfficeList"] as! NSArray

        var mvo : MovieVO

        for row in dailyBoxOfficeList {
            mvo = MovieVO()

            mvo.rank = row["rank"] as? String  // error occur
            mvo.movieNm = row["movieNm"] as? String
            mvo.openDt = row["openDt"] as? String
            mvo.audiCnt = row["audiCnt"] as? String

            self.list.append(mvo)
        }

    } catch {

    }
}

Upvotes: 0

Views: 266

Answers (1)

OOPer
OOPer

Reputation: 47906

The shortest quick fix would be changing this line:

        let dailyBoxOfficeList = boxOfficeResult["dailyBoxOfficeList"] as! NSArray

to something like this:

        let dailyBoxOfficeList = boxOfficeResult["dailyBoxOfficeList"] as! [[String: Any]]

In Swift 3, the Element type of NSArray has become Any, and you cannot apply any methods (including subscript) to Any. In your code, row's type is inferred as Any and you cannot apply subscript to row.


A little more ahead to make your code more Swifty and safer:

enum MyError: Error {
    case badURL
    case notDictionary
    case invalidBoxOfficeResult
    case invalidDailyBoxOfficeList
}
override func viewDidLoad() {

    do {
        //Use `URL` rather than `NSURL`
        guard let apiURI = URL(string: "http://www.kobis.or.kr/kobisopenapi/webservice/rest/boxoffice/searchDailyBoxOfficeList.json?key=a7497a5e700fdff2f3fd468b604d9d18&targetDt=20161020") else {
            throw MyError.badURL
        }

        //Use `Data` rather than `NSData`
        //Avoid using forced unwrapping
        let apidata = try Data(contentsOf: apiURI)

        //Use `String` rather than `NSString`
        NSLog("result = %@", String(data: apidata, encoding: .utf8)!)

        //Cast the resutl of type `Any` as soon as possible
        guard let apiDictionary = try JSONSerialization.jsonObject(with: apidata) as? [String: Any] else {
            throw MyError.notDictionary
        }

        //Cast the resutl of type `Any` as soon as possible
        guard let boxOfficeResult = apiDictionary["boxOfficeResult"] as? [String: Any] else {
            throw MyError.invalidBoxOfficeResult
        }

        //Cast the resutl of type `Any` as soon as possible
        guard let dailyBoxOfficeList = boxOfficeResult["dailyBoxOfficeList"] as? [[String: String]] else {
            throw MyError.invalidDailyBoxOfficeList
        }

        for row in dailyBoxOfficeList {
            var mvo = MovieVO() //<- Assuming `MovieVO` is a struct, use `let` if it is a class

            mvo.rank = row["rank"]
            mvo.movieNm = row["movieNm"]
            mvo.openDt = row["openDt"]
            mvo.audiCnt = row["audiCnt"]

            self.list.append(mvo)
        }

    } catch {
        print(error) //<- You should not ignore errors
    }
}

And a little more...

Data(contentsOf:) (or NSData(contentsOf:)) may consume indefinite time and blocks the main thread until the whole data is received. If you are writing an app for App Store, such an app has risk to be rejected. Try loading the contents in a background thread.

Upvotes: 1

Related Questions