您的位置:首页 > 移动开发 > IOS开发

iOS学习- 24 Core Data by Tutorials - CH04

2016-07-04 00:17 567 查看
1.) Bubble tea finder APP

data model:



View Controller:



JSON Data File:

{

  "meta": {

    "code": 200

  },

  "response": {

    "venues": [

               {

               "id": "4e3c89c8aeb73139a16d84ee",

               "name": "Kung Fu Tea 功夫茶",

               "contact": {

               "phone": "2123343536",

               "formattedPhone": "(212) 334-3536"

               },

               "location": {

               "address": "234 Canal St",

               "crossStreet": "at Centre St.",

               "lat": 40.717854,

               "lng": -74.000208,

               "distance": 4787,

               "postalCode": "10013",

               "cc": "US",

               "city": "New York",

               "state": "NY",

               "country": "United States",

               "formattedAddress": [

                                    "234 Canal St (at Centre St.)",

                                    "New York, NY 10013",

                                    "United States"

                                    ]

               },

               "categories": [

                              {

                              "id": "52e81612bcbc57f1066b7a0c",

                              "name": "Bubble Tea Shop",

                              "pluralName": "Bubble Tea Shops",

                              "shortName": "Bubble Tea",

                              "icon": {

                              "prefix": "https://ss1.4sqi.net/img/categories_v2/food/bubble_",

                              "suffix": ".png"

                              },

                              "primary": true

                              }

                              ],

               "verified": true,

               "stats": {

               "checkinsCount": 6820,

               "usersCount": 3530,

               "tipCount": 60

               },

               "price":{

               "tier":1,

               "message":"Cheap",

               "currency":"$"

               },

               "menu": {

               "type": "Menu",

               "label": "Menu",

               "anchor": "View Menu",

               "url": "https://foursquare.com/v/kung-fu-tea-%E5%8A%9F%E5%A4%AB%E8%8C%B6/4e3c89c8aeb73139a16d84ee/menu",

               "mobileUrl": "https://foursquare.com/v/4e3c89c8aeb73139a16d84ee/device_menu"

               },

               "specials": {

               "count": 0,

               "items": []

               },

               "hereNow": {

               "count": 0,

               "summary": "0 people here",

               "groups": []

               },

               "referralId": "v-1408917566"

               },

               {

               "id": "535aabd5498e00b596216d81",

               "name": "Vivi Bubble Tea",

...

CoreDataStatck.swift

/*

 * Copyright (c) 2016 Razeware LLC

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to deal

 * in the Software without restriction, including without limitation the rights

 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

 * copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

 * THE SOFTWARE.

 */

import CoreData

class CoreDataStack {

  

  let modelName = "Bubble_Tea_Finder"

  

  lazy var context: NSManagedObjectContext = {

    

    var managedObjectContext = NSManagedObjectContext(

      concurrencyType: .MainQueueConcurrencyType)

    

    managedObjectContext.persistentStoreCoordinator = self.psc

    return managedObjectContext

    }()

  

  private lazy var psc: NSPersistentStoreCoordinator = {

    

    let coordinator = NSPersistentStoreCoordinator(

      managedObjectModel: self.managedObjectModel)

    

    let url = self.applicationDocumentsDirectory

      .URLByAppendingPathComponent(self.modelName)

    

    do {

      let options =

      [NSMigratePersistentStoresAutomaticallyOption : true]

      

      try coordinator.addPersistentStoreWithType(

        NSSQLiteStoreType, configuration: nil, URL: url,

        options: options)

    } catch  {

      print("Error adding persistent store.")

    }

    

    return coordinator

    }()

  

  private lazy var managedObjectModel: NSManagedObjectModel = {

    

    let modelURL = NSBundle.mainBundle()

      .URLForResource(self.modelName,

        withExtension: "momd")!

    return NSManagedObjectModel(contentsOfURL: modelURL)!

    }()

  

  private lazy var applicationDocumentsDirectory: NSURL = {

    let urls = NSFileManager.defaultManager().URLsForDirectory(

      .DocumentDirectory, inDomains: .UserDomainMask)

    return urls[urls.count-1]

    }()

  

  func saveContext () {

    if context.hasChanges {

      do {

        try context.save()

      } catch let error as NSError {

        print("Error: \(error.localizedDescription)")

        abort()

      }

    }

  }

}

AppDelegate.swift

/*

 * Copyright (c) 2016 Razeware LLC

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to deal

 * in the Software without restriction, including without limitation the rights

 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

 * copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

 * THE SOFTWARE.

 */

import UIKit

import CoreData

@UIApplicationMain

class AppDelegate: UIResponder, UIApplicationDelegate {

  

  var window: UIWindow?

  lazy var  coreDataStack = CoreDataStack()

  

  

  func application(application: UIApplication,

    didFinishLaunchingWithOptions

    launchOptions: [NSObject: AnyObject]?) -> Bool {

      

      importJSONSeedDataIfNeeded()

      

      let navController = window!.rootViewController as! UINavigationController

      let viewController = navController.topViewController as! ViewController

      viewController.coreDataStack = coreDataStack

      

      return true

  }

  

  func applicationWillTerminate(application: UIApplication) {

    coreDataStack.saveContext()

  }

  

  func importJSONSeedDataIfNeeded() {

    

    let fetchRequest = NSFetchRequest(entityName: "Venue")

    var error: NSError? = nil

    

    let results =

    coreDataStack.context.countForFetchRequest(fetchRequest,

      error: &error)

    

    if (results == 0) {

      

      do {

        let results =

        try coreDataStack.context.executeFetchRequest(fetchRequest) as! [Venue]

        

        for object in results {

          let team = object as Venue

          coreDataStack.context.deleteObject(team)

        }

        

        coreDataStack.saveContext()

        importJSONSeedData()

        

      } catch let error as NSError {

        print("Error fetching: \(error.localizedDescription)")

      }

    }

  }

  

  func importJSONSeedData() {

    let jsonURL = NSBundle.mainBundle().URLForResource("seed", withExtension: "json")

    let jsonData = NSData(contentsOfURL: jsonURL!)

    let venueEntity = NSEntityDescription.entityForName("Venue", inManagedObjectContext: coreDataStack.context)

    let locationEntity = NSEntityDescription.entityForName("Location", inManagedObjectContext: coreDataStack.context)

    let categoryEntity = NSEntityDescription.entityForName("Category", inManagedObjectContext: coreDataStack.context)

    let priceEntity = NSEntityDescription.entityForName("PriceInfo", inManagedObjectContext: coreDataStack.context)

    let statsEntity = NSEntityDescription.entityForName("Stats", inManagedObjectContext: coreDataStack.context)

    

    do {

      let jsonDict = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: .AllowFragments) as! NSDictionary

      let jsonArray = jsonDict.valueForKeyPath("response.venues") as! NSArray

      

      for jsonDictionary in jsonArray {

        

        let venueName = jsonDictionary["name"] as? String

        let venuePhone = jsonDictionary.valueForKeyPath("contact.phone") as? String

        let specialCount = jsonDictionary.valueForKeyPath("specials.count") as? NSNumber

        

        let locationDict = jsonDictionary["location"] as! NSDictionary

        let priceDict = jsonDictionary["price"] as! NSDictionary

        let statsDict = jsonDictionary["stats"] as! NSDictionary

        

        let location = Location(entity: locationEntity!, insertIntoManagedObjec
e575
tContext: coreDataStack.context)

        location.address = locationDict["address"] as? String

        location.city = locationDict["city"] as? String

        location.state = locationDict["state"] as? String

        location.zipcode = locationDict["postalCode"] as? String

        location.distance = locationDict["distance"] as? NSNumber

        

        let category = Category(entity: categoryEntity!, insertIntoManagedObjectContext: coreDataStack.context)

        

        let priceInfo = PriceInfo(entity: priceEntity!, insertIntoManagedObjectContext: coreDataStack.context)

        priceInfo.priceCategory = priceDict["currency"] as? String

        

        let stats = Stats(entity: statsEntity!, insertIntoManagedObjectContext: coreDataStack.context)

        stats.checkinsCount = statsDict["checkinsCount"] as? NSNumber

        stats.usersCount = statsDict["userCount"] as? NSNumber

        stats.tipCount = statsDict["tipCount"] as? NSNumber

        

        let venue = Venue(entity: venueEntity!, insertIntoManagedObjectContext: coreDataStack.context)

        venue.name = venueName

        venue.phone = venuePhone

        venue.specialCount = specialCount

        venue.location = location

        venue.category = category

        venue.priceInfo = priceInfo

        venue.stats = stats

      }

      

      coreDataStack.saveContext()

    } catch let error as NSError {

      print("Deserialization error: \(error.localizedDescription)")

    }

  }


  

}



ViewController.swift

/*

 * Copyright (c) 2016 Razeware LLC

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to deal

 * in the Software without restriction, including without limitation the rights

 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

 * copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

 * THE SOFTWARE.

 */

import UIKit

import CoreData

let filterViewControllerSegueIdentifier = "toFilterViewController"

let venueCellIdentifier = "VenueCell"

class ViewController: UIViewController {

  

  @IBOutlet weak var tableView: UITableView!

  var coreDataStack: CoreDataStack!

    var fetchRequest: NSFetchRequest!

    var venues: [Venue]! = []

    var asyncFetchRequest: NSAsynchronousFetchRequest!

    

  override func viewDidLoad() {

    super.viewDidLoad()

    

    let batchUpdate = NSBatchUpdateRequest(entityName: "Venue")

    

    batchUpdate.propertiesToUpdate = ["favorite": NSNumber(bool: true)]

    batchUpdate.affectedStores = coreDataStack.context.persistentStoreCoordinator!.persistentStores

    batchUpdate.resultType = .UpdatedObjectsCountResultType

    

    do {

        let batchResult = try coreDataStack.context.executeRequest(batchUpdate) as! NSBatchUpdateResult

        print("Records updated \(batchResult.result!)")

    } catch let error as NSError {

        print("Could not update \(error), \(error.userInfo)")

    }

    

    

    //let model = coreDataStack.context.persistentStoreCoordinator!.managedObjectModel

    

    //fetchRequest = model.fetchRequestTemplateForName("FetchRequest")

    

    //1

    fetchRequest = NSFetchRequest(entityName: "Venue")

    

    //2

    asyncFetchRequest =

        NSAsynchronousFetchRequest(fetchRequest: fetchRequest)

        { [unowned self] (result: NSAsynchronousFetchResult! )

            -> Void in

            self.venues = result.finalResult as! [Venue]

            self.tableView.reloadData()

    }

    

    //3

    do {

        try coreDataStack.context.executeRequest(asyncFetchRequest)

    } catch let error as NSError {

        print("Could not fetch \(error), \(error.userInfo)")

    }

    

    //fetchAndReload()

  }

    func fetchAndReload() {

        do {

            venues = try coreDataStack.context.executeFetchRequest(fetchRequest) as! [Venue]

            tableView.reloadData()

        } catch let error as NSError {

            print("Could not fetch \(error), \(error.userInfo)")

        }

    }

    

  override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    

    if segue.identifier == filterViewControllerSegueIdentifier {

        let navController = segue.destinationViewController as! UINavigationController

        

        let filterVC = navController.topViewController as! FilterViewController

        filterVC.coreDataStack = coreDataStack

        

        filterVC.delegate = self

    

    }

  }

  

  @IBAction func unwindToVenuListViewController(segue: UIStoryboardSegue) {

    

  }

}

extension ViewController: UITableViewDataSource {

  

  func tableView(tableView: UITableView,

    numberOfRowsInSection section: Int) -> Int {

    //return 10

    return venues.count

  }

  

  func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier(venueCellIdentifier)!

    //cell.textLabel!.text = "Bubble Tea Venue"

    //cell.detailTextLabel!.text = "Price Info"

    let venue = venues[indexPath.row]

    cell.textLabel!.text = venue.name

    cell.detailTextLabel!.text = venue.priceInfo?.priceCategory

    return cell

  }

}

extension ViewController: FilterViewControllerDelegate {

    func filterViewController(filter: FilterViewController, didSelectPredicate predicate: NSPredicate?, sortDescriptor: NSSortDescriptor?) {

        fetchRequest.predicate = nil

        fetchRequest.sortDescriptors = nil

        

        if let fetchPredicate = predicate {

            fetchRequest.predicate = fetchPredicate

        }

        

        if let sr = sortDescriptor {

            fetchRequest.sortDescriptors = [sr]

        }

        

        fetchAndReload()

    }

}

FilterViewController.swift

/*

 * Copyright (c) 2016 Razeware LLC

 *

 * Permission is hereby granted, free of charge, to any person obtaining a copy

 * of this software and associated documentation files (the "Software"), to deal

 * in the Software without restriction, including without limitation the rights

 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

 * copies of the Software, and to permit persons to whom the Software is

 * furnished to do so, subject to the following conditions:

 *

 * The above copyright notice and this permission notice shall be included in

 * all copies or substantial portions of the Software.

 *

 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

 * THE SOFTWARE.

 */

import UIKit

import CoreData

protocol FilterViewControllerDelegate: class {

    func filterViewController(filter: FilterViewController, didSelectPredicate predicate:NSPredicate?, sortDescriptor:NSSortDescriptor?)

}

class FilterViewController: UITableViewController {

  

  @IBOutlet weak var firstPriceCategoryLabel: UILabel!

  @IBOutlet weak var secondPriceCategoryLabel: UILabel!

  @IBOutlet weak var thirdPriceCategoryLabel: UILabel!

  @IBOutlet weak var numDealsLabel: UILabel!

  

  //Price section

  @IBOutlet weak var cheapVenueCell: UITableViewCell!

  @IBOutlet weak var moderateVenueCell: UITableViewCell!

  @IBOutlet weak var expensiveVenueCell: UITableViewCell!

  

  //Most popular section

  @IBOutlet weak var offeringDealCell: UITableViewCell!

  @IBOutlet weak var walkingDistanceCell: UITableViewCell!

  @IBOutlet weak var userTipsCell: UITableViewCell!

  

  //Sort section

  @IBOutlet weak var nameAZSortCell: UITableViewCell!

  @IBOutlet weak var nameZASortCell: UITableViewCell!

  @IBOutlet weak var distanceSortCell: UITableViewCell!

  @IBOutlet weak var priceSortCell: UITableViewCell!

    var coreDataStack: CoreDataStack!

    

    weak var delegate: FilterViewControllerDelegate?

    var selectedSortDescriptor: NSSortDescriptor?

    var selectedPredicate: NSPredicate?

    

    lazy var nameSortDescriptor: NSSortDescriptor = {

        var sd = NSSortDescriptor(key: "name", ascending: true, selector: "localizedStandardCompare:")

        return sd

    }()

    lazy var distanceSortDescriptor: NSSortDescriptor = {

        var sd = NSSortDescriptor(key: "location.distance", ascending: true)

        return sd

    } ()

    

    lazy var priceSortDescriptor: NSSortDescriptor = {

        var sd = NSSortDescriptor(key: "priceInfo.priceCategory", ascending: true)

        return sd

    }()

    

    lazy var offeringDealPredicate: NSPredicate = {

        var pr = NSPredicate(format: "specialCount > 0")

        return pr

    }()

    

    lazy var walkingDistancePredicate: NSPredicate = {

        var pr = NSPredicate(format: "location.distance < 500")

        return pr

    }()

    

    lazy var hasUserTipsPredicate: NSPredicate = {

        var pr = NSPredicate(format: "stats.tipCount > 0")

        return pr

    }()

    

    

    //populate $ yuan count to cell

    

    lazy var cheapVenuePredicate: NSPredicate = {

        var predicate = NSPredicate(format: "priceInfo.priceCategory == %@", "$")

        return predicate

    }()

    //populate $$ yuan venue count to cell

    lazy var moderateVenuePredicate: NSPredicate = {

        var predicate = NSPredicate(format: "priceInfo.priceCategory == %@", "$$")

        return predicate

    } ()

    

    //populate $$$ yuan venue count to cell

    lazy var expensiveVenuePredicate: NSPredicate = {

        var predicate = NSPredicate(format: "priceInfo.priceCategory == %@", "$$$")

        return predicate

    } ()

    

    

    func populateCheapVenueCountLabel() {

        //$ fetch request

        let fetchRequest = NSFetchRequest(entityName: "Venue")

        fetchRequest.resultType = .CountResultType

        fetchRequest.predicate = cheapVenuePredicate

        

        do {

            let results = try coreDataStack.context.executeFetchRequest(fetchRequest) as! [NSNumber]

            let count = results.first!.integerValue

            firstPriceCategoryLabel.text = "\(count) bubble tea places"

            

        } catch let error as NSError {

            print ("Could not fetch \(error), \(error.userInfo)")

        }

    }

    

    func populateModerateVenueCountLabel() {

        // $$ fetch request

        let fetchRequest = NSFetchRequest(entityName: "Venue")

        fetchRequest.resultType = .CountResultType

        fetchRequest.predicate = moderateVenuePredicate

        

        do {

            let results = try coreDataStack.context.executeFetchRequest(fetchRequest) as! [NSNumber]

            let count = results.first!.integerValue

            secondPriceCategoryLabel.text = "\(count) bubble tea places"

        } catch let error as NSError {

            print("Could not fetch \(error), \(error.userInfo)")

        }

    }

    

    func populateExpensiveVenueCountLabel() {

        // $$$ fetch request

        let fetchRequst = NSFetchRequest(entityName: "Venue")

        fetchRequst.predicate = expensiveVenuePredicate

        

        var error: NSError?

        let count = coreDataStack.context.countForFetchRequest(fetchRequst, error: &error)

        

        if count != NSNotFound {

            thirdPriceCategoryLabel.text = "\(count) bubble tea places"

        } else {

            print("Could not fetch \(error), \(error?.userInfo)")

        }

    }

    

    func populateDealsCountLabel()  {

        //1

        let fetchRequest = NSFetchRequest(entityName: "Venue")

        fetchRequest.resultType = .DictionaryResultType

        

        //2

        let sumExpressionDesc = NSExpressionDescription()

        sumExpressionDesc.name = "sumDeals"

        

        //3

        sumExpressionDesc.expression = NSExpression(forFunction: "sum:", arguments: [NSExpression(forKeyPath: "specialCount")])

        sumExpressionDesc.expressionResultType = .Integer32AttributeType

        

        //4

        fetchRequest.propertiesToFetch = [sumExpressionDesc]

        

        //5

        do {

            let results = try coreDataStack.context.executeFetchRequest(fetchRequest) as! [NSDictionary]

            let resultDict = results.first!

            let numDeals = resultDict["sumDeals"]

            numDealsLabel.text = "\(numDeals!) total deals"

        } catch let error as NSError {

            print("Counld not fetch \(error), \(error.userInfo)")

        }

    }

    

    override func viewDidLoad() {

        super.viewDidLoad()

        

        //count $

        populateCheapVenueCountLabel()

        

        //count $$

        populateModerateVenueCountLabel()

        

        //count $$$

        populateExpensiveVenueCountLabel()

        

        //populate specialCount

        populateDealsCountLabel()

    }

    

  //MARK - UITableViewDelegate methods

  

  override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

  

    let cell = tableView.cellForRowAtIndexPath(indexPath)!

    switch cell {

        //Price section

    case cheapVenueCell:

        selectedPredicate = cheapVenuePredicate

    case moderateVenueCell:

        selectedPredicate = moderateVenuePredicate

    case expensiveVenueCell:

        selectedPredicate = expensiveVenuePredicate

        //Most Popular section

    case offeringDealCell:

        selectedPredicate = offeringDealPredicate

    case walkingDistanceCell:

        selectedPredicate = walkingDistancePredicate

    case userTipsCell:

        selectedPredicate = hasUserTipsPredicate

        //Sort By section

    case nameAZSortCell:

        selectedSortDescriptor = nameSortDescriptor

    case nameZASortCell:

        selectedSortDescriptor = nameSortDescriptor.reversedSortDescriptor as? NSSortDescriptor

    case distanceSortCell:

        selectedSortDescriptor = distanceSortDescriptor

    case priceSortCell:

        selectedSortDescriptor = priceSortDescriptor

    default:

        print("default case")

    }

    

    cell.accessoryType = .Checkmark

  

  }

  

  // MARK - UIButton target action

  

  @IBAction func saveButtonTapped(sender: UIBarButtonItem) {

    delegate!.filterViewController(self, didSelectPredicate: selectedPredicate, sortDescriptor: selectedSortDescriptor)

    

    dismissViewControllerAnimated(true, completion:nil)

  }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios app swift