Creating a function on a parent class that can be

2019-09-07 02:02发布

问题:

I'm trying to create a function in a parent class that can be accessible to it's child classes. The issue I'm having is part of the function is referring to an init that needs to happen in the child class. I get an error:

Argument passed to call that takes no arguments

I'm not completely sure how to make the function available to it's child classes without copy and pasting it inside each child class.

Here is the parent class:

class JSONObject: NSObject {


  static func updateResultsDictionary(urlExtension: String, completion:
    @escaping (JSONObject?) -> Void) {

    let nm = NetworkManager.sharedManager

    _ = nm.getJSONData(urlExtension: urlExtension) {data in

      guard let jsonDictionary = nm.parseJSONFromData(data), let

        resultDictionaries = jsonDictionary["result"] as?

          [[String : Any]] else {

            completion(nil)

            return
      }

      for resultsDictionary in resultDictionaries {

        let jsonInfo = JSONObject(resultsDictionary: resultsDictionary)// Here is where the error "Argument passed to call that takes no arguments" happens

        completion(jsonInfo)

      }
    }
  }
}

This is a sample child class:

class AirBnBObject: JSONObject {

  var airbnbUS: Int
  var airbnbLocal: Int

  init(airbnbUS: Int, airbnbLocal: Int){

    self.airbnbUS = airbnbUS
    self.airbnbLocal = airbnbLocal
  }

  init(resultsDictionary:[String: Any]){
    guard let cost = resultsDictionary["cost"] as? [String: Any],
      let airbnb = cost["airbnb_median"] as? [String : Any],
      let usd = airbnb["USD"] as? Int,
      let chf = airbnb["CHF"] as? Int
      else {
        airbnbUS = 0
        airbnbLocal = 0
        return
    }

    airbnbUS = usd
    airbnbLocal = chf
  }
}

回答1:

I would move towards using a protocol instead of a class, that way you can design your JSONObject to require any classes that implement it to also implement init(resultsDictionary: [String:Any]). This allows you to write your updateResultsDictionary function in a protocol extension (which causes any implementing class to also inherit that function).

The protocol would look like this:

protocol JSONObject: class, NSObjectProtocol {

    init(resultsDictionary: [String:Any])

}

extension JSONObject {

    static func updateResultsDictionary<T: JSONObject>(urlExtension: String, completion:
        @escaping (_ jsonObject: T?) -> Void) {

        let nm = NetworkManager.sharedManager

        _ = nm.getJSONData(urlExtension: urlExtension) {data in

            guard let jsonDictionary = nm.parseJSONFromData(data), 
                  let resultDictionaries = jsonDictionary["result"] as? [[String : Any]] else {

                        completion(nil)

                        return
            }

            for resultsDictionary in resultDictionaries {

                let jsonInfo = T(resultsDictionary: resultsDictionary)

                completion(jsonInfo)

            }

        }

    }

}

The function needs to be generic in order to avoid the error you were seeing 'Protocol type cannot be instantiated'. Using class T which conforms to JSONObject rather than JSONObject itself fixes the error. (Note that in use T would be your conforming class, see below)


and any implementing class would look something like this:

class AirBnBObject: NSObject, JSONObject {

    var airbnbUS: Int
    var airbnbLocal: Int

    init(airbnbUS: Int, airbnbLocal: Int){

        self.airbnbUS = airbnbUS
        self.airbnbLocal = airbnbLocal
    }

    required init(resultsDictionary:[String: Any]){
        guard let cost = resultsDictionary["cost"] as? [String: Any],
            let airbnb = cost["airbnb_median"] as? [String : Any],
            let usd = airbnb["USD"] as? Int,
            let chf = airbnb["CHF"] as? Int
            else {
                airbnbUS = 0
                airbnbLocal = 0
                return
        }

        airbnbUS = usd
        airbnbLocal = chf

    }

}

To use your extension function with this class you need to do it this way:

AirBnBObject.updateResultsDictionary(urlExtension: "") { (_ jsonObject: AirBnBObject?) -> Void in
    print("update results dictionary")
}


标签: ios swift class