Passing generic Class as argument to function in swift

徘徊边缘 提交于 2019-11-28 11:38:46

问题


Below is my method in which there is fetch I make on a Managed object Class Appointment. I need to use same function for other similar managed object Classes. How do I pass different "Class" as parameter every time as I need. And also use it to fetch as I have currently "Appointment" Class. I might need to use Generics may be. Dont know how though.

func getAppointmentArray(aPredicate : String , aModel : Any) -> [Any]
{
    var apptArr = [Any]()
    let fetchRequest = NSFetchRequest<Appointment>(entityName: "Appointment")
    fetchRequest.returnsObjectsAsFaults = false
    fetchRequest.predicate = NSPredicate(format: aPredicate)
    do{
        let records = try managedObjectContext.fetch(fetchRequest)

        if let records = records as? [NSManagedObject]{
            if !records.isEmpty{

                print("coreData apptmnt result : \(records)")
                var appointment : Appointment?

                for obj in records
                {

                }
            }else{
                print("No records found")
                apptArr = []
            }
        }
    }catch{
        print("Error")
         apptArr = []
    }
   return apptArr
}

回答1:


for the generic you can do something like this:

class FetchingDataHandler<T>{
func getAppointmentArray<T>(forClass : T, aPredicate : String , aModel : Any) -> [Any]
  {
  }
}



回答2:


The good folks at Objc.io provide a really good approach for this. First declare a protocol which inherits 'NSFetchRequestResult' protocol as below.

protocol Managed: class, NSFetchRequestResult {
    static var entityName: String { get }
} 

Now we can provide a very convenient protocol extension for our protocol 'Managed'. We do the check 'Self: NSManagedObject' as we want the static method entity() of the NSManagedObject class to get the 'NSEntityDescription' describing the entity associated with our class. Particularly this way we get the entity name dynamically(and conveniently too) for all our ManagedObjects that conform to our protocol.

extension Managed where Self: NSManagedObject {
    static var entityName: String { return entity().name! }
}

We now improve the protocol extension by providing a method which conveniently creates a fetch request and then calls a configuration block which might be used to configure the created fetch request by whoever calls it. At the end of this method we do a fetch using the created request.

extension Managed where Self: NSManagedObject {
        static var entityName: String { return entity().name! }

        //Continued
        static func fetch(in context: NSManagedObjectContext, configurationBlock: (NSFetchRequest<Self>) -> ()) -> [Self] {
            let request = NSFetchRequest<Self>(entityName: Self.entityName)
            configurationBlock(request)
            return try! context.fetch(request)
        }
}

As you can see we do the following things here:

  • We make good use of protocols and protocol extensions for making our life easy.
  • We get the entity name without needing to write a method for each concrete managed object class that we might create. This is reusable for every managed object class that will conform to 'Managed'
  • The fetch method that we wrote makes use of the dynamic and convenient entityName.
  • The fetch method again makes use of Self which is implementation independent here. This way we make FetchRequests which are generic in itself.
  • We provide a convenient way to configure the request to whoever calls this method.
  • And at atlast we return result after fetching which is also dynamic [Self]

To see our protocol in action we can do this for your case:

class Appointment: NSManagedObject, Managed{
    //properties for attributes
    //etc...
    //Will I get free implementation for entity name and a fetch method
    //without writing extra code ?
    //Yes why not
}

Testing our hard earned knowledge:

let aPredicate = "......
let context: NSManagedObjectContext.....
let appointments = Appointment.fetch(in: context) { fetchRequest in
    //Configuration code like adding predicates and sort descriptors
    fetchRequest.predicate = NSPredicate(format: aPredicate)
}

You can use the same pattern for any other ManagedObjects if they conform to the protocol. Eg a Doctor ManagedObject subclass conforming to our Managed protocol:

let aPredicate = "......
let context: NSManagedObjectContext.....
let doctors = Doctor.fetch(in: context) { fetchRequest in
    //Configuration code like adding predicates and sort descriptors
    fetchRequest.predicate = NSPredicate(format: aPredicate)
}


来源:https://stackoverflow.com/questions/51174234/passing-generic-class-as-argument-to-function-in-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!