19、iOS开发:REST API调用与Core Data使用指南

iOS中REST API与Core Data集成

iOS开发:REST API调用与Core Data使用指南

1. REST API调用

在iOS开发中,我们经常需要与REST API进行交互,获取或发送数据。下面将介绍如何使用 RestClient 类进行GET和POST请求。

1.1 使用RestClient进行GET请求

RestClient 类结合了两个其他的功能,用于处理REST API的请求。要使用这个类,你需要将 RestClient JSONParser JSON 类包含到你的应用中。以下是具体步骤:
1. 创建新的iOS单视图应用 :在Xcode中创建一个新的iOS单视图应用项目。
2. 添加类文件 :将 RestClient JSONParser (清单9 - 1)和 JSON (清单9 - 2)类添加到项目中。
3. 替换 ViewController.swift 内容 :将 ViewController.swift 的内容替换为清单9 - 10的代码。

以下是 RestClient 类的完整代码(清单9 - 9):

import Foundation
public class RestClient {
    public class func Get(url : String, callback : (JSON?, NSError?)->()) {
        let url = NSURL(string: url)
        let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {
            (data, response, error) in
            if let err = error {
                callback(nil, err)
            }
            // attempt to parse
            var parseError : NSError?
            var parsedData = JSONParser.parse(data, error: &parseError)
            if let err = parseError {
                callback(nil, err)
            }
            callback ( parsedData, nil)
        }
        task.resume()
    }
}

以下是使用 RestClient 类的示例代码(清单9 - 10):

import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        RestClient.Get("https://openlibrary.org/works/OL11315329W") { (json, error) -> Void in
            if let err = error {
                println("Error: \(error?.localizedDescription)")
                return
            }
            if let j = json {
                var title = j["title"]?.stringValue
                var revision = j["revision"]?.intValue
                println("Title: \(title!)")
                println("Revision: \(revision!)")
            }
        }
    }
}

运行这个应用,你将在控制台看到类似以下的输出:

Title: Mastering the Art of French Cooking
Revision: 6
1.2 使用RestClient进行POST请求

当你需要向REST API发送POST请求时,可以使用 NSURLSession NSJSONSerialization 的组合。以下是具体步骤:
1. 准备数据 :将需要发送的数据放入一个 [String, AnyObject] 字典中。例如:

var data: [String: AnyObject] = ["name" : "Pea Soup",
    "Ingredients" : "Split Peas, Water, Chicken Broth, Milk, Salt, Onions"]
  1. 调用 RestClient Post 方法
RestClient.Post("http://echo.jsontest.com/status/OK", data: data) { (json, error) -> Void in
    if let err = error {
        println("Error: \(error?.localizedDescription)")
        return
    }
    if let j = json {
        var status = j["status"]?.stringValue
        println("Status: \(status!)")
    }
}

以下是包含 Post 方法的 RestClient 类的完整代码(清单9 - 11):

import Foundation
public class RestClient {
    public class func Get(url : String, callback : (JSON?, NSError?)->()) {
        let url = NSURL(string: url)
        let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {
            (data, response, error) in
            if let err = error {
                callback(nil, err)
            }
            // attempt to parse
            var parseError : NSError?
            var parsedData = JSONParser.parse(data, error: &parseError)
            if let err = parseError {
                callback(nil, err)
            }
            callback ( parsedData, nil)
        }
        task.resume()
    }
    public class func Post(url : String, data : [String: AnyObject], callback : (JSON?, NSError?)->()) {
        let url = NSURL(string: url)
        var request = NSMutableURLRequest(URL: url!)
        request.HTTPMethod = "POST"
        request.addValue("application/json", forHTTPHeaderField: "Content-type")
        request.addValue("application/json", forHTTPHeaderField: "Accept")
        var paramError : NSError?
        var paramData = NSJSONSerialization.dataWithJSONObject(data,
            options: NSJSONWritingOptions.allZeros, error: &paramError)
        request.HTTPBody = paramData
        println("POST DATA")
        println(NSJSONSerialization.JSONObjectWithData(paramData, options: nil, error: nil)!)
        let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
            (data, response, error) in
            if let err = error {
                callback(nil, err)
            }
            // attempt to parse
            var parseError : NSError?
            var parsedData = JSONParser.parse(data, error: &parseError)
            if let err = parseError {
                callback(nil, err)
            }
            callback ( parsedData, nil)
        }
        task.resume()
    }
}

以下是 ViewController.swift 中使用 Post 方法的代码(清单9 - 12):

import UIKit
class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        var data: [String: AnyObject] = [ "name" : "Pea Soup",
            "Ingredients" : "Split Peas, Water, Chicken Broth, Milk, Salt, Onions" ]
        RestClient.Post("http://echo.jsontest.com/status/OK", data: data) { (json, error) -> Void in
            if let err = error {
                println("Error: \(error?.localizedDescription)")
                return
            }
            if let j = json {
                var status = j["status"]?.stringValue
                println("Status: \(status!)")
            }
        }
    }
}

运行这个应用时,会向JSONTest.com发送请求,请确保你已连接到互联网。在发送数据之前,数据的JSON版本会打印到控制台,你可以看到其格式。JSONTest.com会返回一个包含单个键值对的JSON字符串,完成处理程序会打印出状态值。你应该会在控制台看到类似以下的输出:

POST DATA
{
    Ingredients = "Split Peas, Water, Chicken Broth, Milk, Salt, Onions";
    name = "Pea Soup";
}
Status: OK
2. Core Data使用

Core Data是许多数据驱动的iOS和OS X应用的核心。它可用于存储、在网络和设备间同步信息,以及快速访问大型数据集。以下将介绍如何使用Core Data进行数据管理。

2.1 创建数据模型

当你想要设计使用Core Data持久化的实体时,需要创建一个数据模型。以下是具体步骤:
1. 添加Core Data框架 :在Xcode中创建一个新的iOS主 - 详细应用,保存项目后,在项目中添加Core Data框架。选择应用目标“Core Data”和“Build Phases”选项卡,在“Link Binary With Libraries”下点击加号按钮,从列表中选择“CoreData.framework”并点击添加。
2. 创建数据模型文件 :在项目中添加一个新文件,在新文件对话框的“Core Data”部分选择“Data Model”,将新文件保存为 RecipeBook
3. 定义实体和属性 :打开数据模型文件,在Xcode的数据模型编辑器中,点击“Add Entity”添加一个新实体,将其重命名为 Recipe 。为 Recipe 实体添加属性,如 name (类型为 String )、 serves (类型为 Integer 32 )和 recipeDescription (类型为 String )。在“Relationships”部分添加一个名为 ingredients 的关系。
4. 创建另一个实体 :创建一个名为 Ingredient 的新实体,为其添加 measurement (类型为 Int16 )和 ingredient (类型为 String )属性。在“Relationship”部分添加一个名为 parentRecipe 的关系,将其目标设置为 Recipe 类,并将逆关系设置为 ingredients 。回到 Recipe 实体,完成 ingredients 关系的设置,将目标设置为 Ingredient 类,逆关系设置为 parentRecipe

2.2 创建模型类

有了数据模型后,你可以使用Xcode为实体生成类。以下是具体步骤:
1. 打开数据模型 :在Xcode中打开数据模型文件。
2. 生成实体代码 :在菜单栏中选择“Editor” -> “Create NSManagedObject Subclass”。在弹出的对话框中,确保选择了 RecipeBook 数据模型,然后点击“Next”。
3. 选择实体 :选择 Recipe Ingredient 实体,点击“Next”。
4. 选择语言和保存位置 :确保选择了Swift作为语言,最后选择类文件的保存位置。

以下是生成的 Recipe 实体类代码(清单10 - 1):

import Foundation
import CoreData
class Recipe: NSManagedObject {
    @NSManaged var name: String
    @NSManaged var recipeDescription: String
    @NSManaged var serves: NSNumber
    @NSManaged var ingredients: NSOrderedSet
}

以下是生成的 Ingredient 实体类代码(清单10 - 2):

import Foundation
import CoreData
class Ingredient: NSManagedObject {
    @NSManaged var ingredient: String
    @NSManaged var measurement: NSNumber
    @NSManaged var parentRecipe: Recipe
}
2.3 创建数据存储

你需要创建或打开一个现有的数据存储。可以通过实例化 NSManagedObjectModel NSPersistentStoreCoordinator 来实现。以下是具体步骤:
1. 创建辅助类文件 :在项目中创建一个新文件 CoreDataHelper.swift ,用于包含辅助类。
2. 定义类和初始化器 :在 CoreDataHelper.swift 中定义 CoreDataHelper 类和初始化器,设置模型名称和数据文件名称的属性。

import Foundation
import CoreData
public class CoreDataHelper {
    var modelName : String
    var datastoreFileName : String
    init( modelName : String, datastoreFileName : String) {
        self.modelName = modelName
        self.datastoreFileName = datastoreFileName
    }
}
  1. 创建 NSManagedObjectModel 实例 :使用 lazy 关键字定义一个 NSManagedObjectModel 属性,并使用立即调用的闭包进行初始化。
lazy var managedObjectModel: NSManagedObjectModel = {
    let modelURL = NSBundle.mainBundle().URLForResource("RecipeBook", withExtension: "momd")!
    return NSManagedObjectModel(contentsOfURL: modelURL)!
}()
  1. 创建 NSPersistentStoreCoordinator 实例 :同样使用 lazy 关键字定义一个 NSPersistentStoreCoordinator 属性。
lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
    var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
    let documentsDirectory : NSURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last as! NSURL
    let url = documentsDirectory.URLByAppendingPathComponent(self.datastoreFileName)
    var error: NSError? = nil
    let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
    if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options, error: &error) == nil {
        coordinator = nil
        var dict = [String: AnyObject]()
        dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
        dict[NSLocalizedFailureReasonErrorKey] = "There was an error creating or loading the data store"
    }
    return coordinator
}()

在创建数据存储时,需要处理可能出现的错误。如果数据存储无法打开,文件可能已损坏或迁移时出现问题。你可以使用开源工具“SQLite Database Browser for OS X”打开和编辑SQLite文件,同时可以通过启用iTunes文件共享让用户将文件发送给你进行修复。

通过以上步骤,你可以在iOS应用中实现REST API调用和Core Data数据管理,为应用的数据交互和存储提供强大的支持。

2.4 创建托管对象上下文

托管对象上下文(Managed Object Context)是 Core Data 中的一个重要概念,它充当对象的暂存区,用于管理对象的生命周期和跟踪对象的变化。以下是创建托管对象上下文的步骤:

  1. CoreDataHelper 类中添加方法 :在 CoreDataHelper.swift 文件中,为 CoreDataHelper 类添加一个方法来创建托管对象上下文。
import Foundation
import CoreData
public class CoreDataHelper {
    var modelName : String
    var datastoreFileName : String
    init( modelName : String, datastoreFileName : String) {
        self.modelName = modelName
        self.datastoreFileName = datastoreFileName
    }

    lazy var managedObjectModel: NSManagedObjectModel = {
        let modelURL = NSBundle.mainBundle().URLForResource("RecipeBook", withExtension: "momd")!
        return NSManagedObjectModel(contentsOfURL: modelURL)!
    }()

    lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = {
        var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
        let documentsDirectory : NSURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).last as! NSURL
        let url = documentsDirectory.URLByAppendingPathComponent(self.datastoreFileName)
        var error: NSError? = nil
        let options = [NSMigratePersistentStoresAutomaticallyOption: true, NSInferMappingModelAutomaticallyOption: true]
        if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: options, error: &error) == nil {
            coordinator = nil
            var dict = [String: AnyObject]()
            dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data"
            dict[NSLocalizedFailureReasonErrorKey] = "There was an error creating or loading the data store"
        }
        return coordinator
    }()

    func managedObjectContext() -> NSManagedObjectContext {
        let context = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
        context.persistentStoreCoordinator = self.persistentStoreCoordinator
        return context
    }
}
  1. 使用托管对象上下文 :在需要使用托管对象上下文的地方,调用 CoreDataHelper 类的 managedObjectContext() 方法。
let helper = CoreDataHelper(modelName: "RecipeBook", datastoreFileName: "RecipeBook.sqlite")
let context = helper.managedObjectContext()
2.5 添加新实体

当你需要向 Core Data 存储中添加新实体时,可以使用托管对象上下文。以下是添加新 Recipe 实体的步骤:

  1. 获取托管对象上下文 :使用前面创建的 CoreDataHelper 类获取托管对象上下文。
let helper = CoreDataHelper(modelName: "RecipeBook", datastoreFileName: "RecipeBook.sqlite")
let context = helper.managedObjectContext()
  1. 创建新实体 :使用 NSEntityDescription.insertNewObjectForEntityForName 方法创建新的 Recipe 实体。
let newRecipe = NSEntityDescription.insertNewObjectForEntityForName("Recipe", inManagedObjectContext: context) as! Recipe
newRecipe.name = "New Recipe"
newRecipe.serves = 4
newRecipe.recipeDescription = "This is a new recipe."
  1. 保存上下文 :调用托管对象上下文的 save 方法将更改保存到数据存储中。
do {
    try context.save()
    print("New recipe saved successfully.")
} catch {
    let nserror = error as NSError
    print("Unresolved error \(nserror), \(nserror.userInfo)")
}
2.6 创建 NSFetchRequest

NSFetchRequest 用于从 Core Data 存储中检索数据。以下是创建 NSFetchRequest 并执行查询的步骤:

  1. 创建 NSFetchRequest 对象 :指定要检索的实体名称。
let fetchRequest = NSFetchRequest(entityName: "Recipe")
  1. 设置查询条件(可选) :可以使用谓词( NSPredicate )来过滤查询结果。
let predicate = NSPredicate(format: "serves > %d", 2)
fetchRequest.predicate = predicate
  1. 执行查询 :使用托管对象上下文的 executeFetchRequest 方法执行查询。
let helper = CoreDataHelper(modelName: "RecipeBook", datastoreFileName: "RecipeBook.sqlite")
let context = helper.managedObjectContext()
do {
    let results = try context.executeFetchRequest(fetchRequest)
    for recipe in results as! [Recipe] {
        print("Recipe name: \(recipe.name)")
    }
} catch {
    let nserror = error as NSError
    print("Unresolved error \(nserror), \(nserror.userInfo)")
}
2.7 使用获取结果控制器填充 UITableView

获取结果控制器( NSFetchedResultsController )可以方便地将 Core Data 查询结果绑定到 UITableView 上。以下是使用获取结果控制器填充 UITableView 的步骤:

  1. 创建获取结果控制器 :在 ViewController 类中创建 NSFetchedResultsController 实例。
import UIKit
import CoreData
class ViewController: UIViewController, UITableViewDataSource, NSFetchedResultsControllerDelegate {
    @IBOutlet weak var tableView: UITableView!
    var fetchedResultsController: NSFetchedResultsController!

    override func viewDidLoad() {
        super.viewDidLoad()
        let helper = CoreDataHelper(modelName: "RecipeBook", datastoreFileName: "RecipeBook.sqlite")
        let context = helper.managedObjectContext()
        let fetchRequest = NSFetchRequest(entityName: "Recipe")
        fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
        fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: context, sectionNameKeyPath: nil, cacheName: nil)
        fetchedResultsController.delegate = self
        do {
            try fetchedResultsController.performFetch()
        } catch {
            let nserror = error as NSError
            print("Unresolved error \(nserror), \(nserror.userInfo)")
        }
        tableView.dataSource = self
    }

    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return fetchedResultsController.sections?.count ?? 0
    }

    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        let sectionInfo = fetchedResultsController.sections![section]
        return sectionInfo.numberOfObjects
    }

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
        let recipe = fetchedResultsController.objectAtIndexPath(indexPath) as! Recipe
        cell.textLabel?.text = recipe.name
        return cell
    }
}
  1. 实现 NSFetchedResultsControllerDelegate 方法 :处理数据变化时的更新操作。
func controllerWillChangeContent(controller: NSFetchedResultsController) {
    tableView.beginUpdates()
}

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
    switch type {
    case .Insert:
        tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
    case .Delete:
        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
    case .Update:
        let cell = tableView.cellForRowAtIndexPath(indexPath!)
        let recipe = controller.objectAtIndexPath(indexPath!) as! Recipe
        cell?.textLabel?.text = recipe.name
    case .Move:
        tableView.deleteRowsAtIndexPaths([indexPath!], withRowAnimation: .Fade)
        tableView.insertRowsAtIndexPaths([newIndexPath!], withRowAnimation: .Fade)
    }
}

func controllerDidChangeContent(controller: NSFetchedResultsController) {
    tableView.endUpdates()
}
2.8 删除项目

当你需要从 Core Data 存储中删除项目时,可以使用托管对象上下文。以下是删除 Recipe 实体的步骤:

  1. 获取要删除的实体 :使用 NSFetchRequest 或其他方式获取要删除的实体。
let helper = CoreDataHelper(modelName: "RecipeBook", datastoreFileName: "RecipeBook.sqlite")
let context = helper.managedObjectContext()
let fetchRequest = NSFetchRequest(entityName: "Recipe")
let predicate = NSPredicate(format: "name == %@", "New Recipe")
fetchRequest.predicate = predicate
do {
    let results = try context.executeFetchRequest(fetchRequest)
    if let recipeToDelete = results.first as? Recipe {
        context.deleteObject(recipeToDelete)
    }
} catch {
    let nserror = error as NSError
    print("Unresolved error \(nserror), \(nserror.userInfo)")
}
  1. 保存上下文 :调用托管对象上下文的 save 方法将更改保存到数据存储中。
do {
    try context.save()
    print("Recipe deleted successfully.")
} catch {
    let nserror = error as NSError
    print("Unresolved error \(nserror), \(nserror.userInfo)")
}
2.9 搜索实体

在 Core Data 中搜索实体可以使用谓词( NSPredicate )来过滤查询结果。以下是搜索 Recipe 实体的示例:

  1. 创建 NSFetchRequest 对象 :指定要检索的实体名称。
let fetchRequest = NSFetchRequest(entityName: "Recipe")
  1. 设置搜索谓词 :根据搜索关键字创建谓词。
let searchText = "New"
let predicate = NSPredicate(format: "name CONTAINS[c] %@", searchText)
fetchRequest.predicate = predicate
  1. 执行查询 :使用托管对象上下文的 executeFetchRequest 方法执行查询。
let helper = CoreDataHelper(modelName: "RecipeBook", datastoreFileName: "RecipeBook.sqlite")
let context = helper.managedObjectContext()
do {
    let results = try context.executeFetchRequest(fetchRequest)
    for recipe in results as! [Recipe] {
        print("Search result: \(recipe.name)")
    }
} catch {
    let nserror = error as NSError
    print("Unresolved error \(nserror), \(nserror.userInfo)")
}

总结

通过以上内容,我们详细介绍了在 iOS 开发中如何进行 REST API 调用和使用 Core Data 进行数据管理。REST API 调用部分涵盖了 GET 和 POST 请求的实现,而 Core Data 使用部分则包括了创建数据模型、模型类、数据存储、托管对象上下文,以及添加、查询、删除和搜索实体等操作。这些技术可以帮助开发者构建功能强大、数据驱动的 iOS 应用。希望本文能对你的 iOS 开发工作有所帮助。

流程图

以下是 Core Data 操作的主要流程:

graph TD;
    A[创建数据模型] --> B[创建模型类];
    B --> C[创建数据存储];
    C --> D[创建托管对象上下文];
    D --> E[添加新实体];
    D --> F[创建 NSFetchRequest];
    F --> G[使用获取结果控制器填充 UITableView];
    D --> H[删除项目];
    D --> I[搜索实体];

表格

操作 步骤
REST API GET 请求 1. 创建新的 iOS 单视图应用;2. 添加类文件;3. 替换 ViewController.swift 内容
REST API POST 请求 1. 准备数据;2. 调用 RestClient Post 方法
创建数据模型 1. 添加 Core Data 框架;2. 创建数据模型文件;3. 定义实体和属性;4. 创建另一个实体
创建模型类 1. 打开数据模型;2. 生成实体代码;3. 选择实体;4. 选择语言和保存位置
创建数据存储 1. 创建辅助类文件;2. 定义类和初始化器;3. 创建 NSManagedObjectModel 实例;4. 创建 NSPersistentStoreCoordinator 实例
创建托管对象上下文 CoreDataHelper 类中添加方法并调用
添加新实体 1. 获取托管对象上下文;2. 创建新实体;3. 保存上下文
创建 NSFetchRequest 1. 创建 NSFetchRequest 对象;2. 设置查询条件(可选);3. 执行查询
使用获取结果控制器填充 UITableView 1. 创建获取结果控制器;2. 实现 NSFetchedResultsControllerDelegate 方法
删除项目 1. 获取要删除的实体;2. 保存上下文
搜索实体 1. 创建 NSFetchRequest 对象;2. 设置搜索谓词;3. 执行查询
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值