实战编程·使用SwiftUI从0到1完成一款iOS笔记App(四)(2)

简介: 实战编程·使用SwiftUI从0到1完成一款iOS笔记App(四)

功能方法

下面我们来创建一些念头笔记用到的方法,在之前的章节中我们实现了新建笔记的功能,但当我们每次重新打开APP时,它又会“恢复”到初始模式,在上一次操作的数据全部清空了。

这是因为我们只是完成了简单的操作而已,而没有实现其核心功能,即把数据存起来。但是我们没有数据库也没有云端,数据存在哪里呢?是的,放在本地,放到本地缓存起来。

在我们创建iOS项目时,系统会创建一个plist文件,作为缓存区,我们可以将数据暂时存储在这里。

加载数据

ViewModel类中,我们需要使用到的基本方法如下代码所示:

//初始化
    init() {
        loadItems()
        saveItems()
    }
  // 获取设备上的文档目录路径
    func documentsDirectory() -> URL {
        FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
    }
    // 获取plist数据文件的路径
    func dataFilePath() -> URL {
        documentsDirectory().appendingPathComponent("IdeaNote.plist")
    }
    // 将数据写入本地存储
    func saveItems() {
        let encoder = PropertyListEncoder()
        do {
            let data = try encoder.encode(noteModels)
            try data.write(to: dataFilePath(), options: Data.WritingOptions.atomic)
        } catch {
            print("Error writing items to file: (error.localizedDescription)")
        }
    }
    // 从本地存储加载数据
    func loadItems() {
        let path = dataFilePath()
        if let data = try? Data(contentsOf: path) {
            let decoder = PropertyListDecoder()
            do {
                noteModels = try decoder.decode([NoteModel].self, from: data)
            } catch {
                print("Error reading items: (error.localizedDescription)")
            }
        }
    }

image.png

上述代码中,首先创建了一个方法documentsDirectory获取设备上的文档目录路径,再指定要获取的目录IdeaNote.plist的方法dataFilePath

获得本地设备目录后,使用saveItems方法将noteModels数组中的数据写入到到本地存储中,当App打开的时候,使用loadItems方法让List列表从本地存储中加载数据遍历列表。

最后在我们App初始化加载的时候,调用loadItems加载数据方法,并调用saveItems方法将数据写入缓存中。

以上是加载本地数据的基本方法。

增删改查

紧接着,我们来实现念头笔记的增删改查的基本方法,如下代码所示:

// 创建笔记
    func addItem(writeTime: String, title: String, content: String) {
        let newItem = NoteModel(writeTime: writeTime, title: title, content: content)
        noteModels.append(newItem)
        saveItems()
    }
    // 获得数据项ID
    func getItemById(itemId: UUID) -> NoteModel? {
        return noteModels.first(where: { $0.id == itemId }) ?? nil
    }
    // 删除笔记
    func deleteItem(itemId: UUID) {
        noteModels.removeAll(where: { $0.id == itemId })
        saveItems()
    }
    // 编辑笔记
    func editItem(item: NoteModel) {
        if let id = noteModels.firstIndex(where: { $0.id == item.id }) {
            noteModels[id] = item
            saveItems()
        }
    }
    // 搜索笔记
    func searchContet() {
        let query = searchText.lowercased()
        DispatchQueue.global(qos: .background).async {
            let filter = self.noteModels.filter { $0.content.lowercased().contains(query) }
            DispatchQueue.main.async {
                self.noteModels = filter
            }
        }
    }

image.png

由于列表中每一行的数据都有对应的ID,因此除了新增数据以外,删改查的基本功能都是通过数据的ID操作的,计算机都是先找到数据,再对数据进行操作。

新建笔记的方法addItem,通过传入对应参数的值,然后将参数的值赋值给NoteModel模型类,再通过append添加的方法添加到noteModels数组中,最后调用saveItems方法保存到本地。

删除笔记的方法deleteItem,需要先获取到指定行数据的ID,这里抽离出了获得数据ID的方法getItemById,通过传入数据ID与NoteModel模型类的ID进行匹配就可以知道是哪一条数据,再调用removeAll删除noteModels数组中指定ID的数据,最后调用saveItems方法保存操作。

编辑笔记的方法editItem,也是传入符合NoteModel模型类的数据,找到它的ID,最后调用saveItems方法保存到本地。

搜索笔记的方法searchContet,先定义用户搜索内容为searchText,再拿用户输入的内容和noteModels数组中的content内容数据做对比,如果符合,就返回符合的数据到noteModels数组中。

其他方法

除此之外,我们将原来在新建笔记页面使用到的获得当前时间的方法,包括判断输入内容是否为空的方法也纳入到ViewModel里面,如下代码所示 :

// 获取当前系统时间
    func getCurrentTime() -> String {
        let dateformatter = DateFormatter()
        dateformatter.dateFormat = "YYYY.MM.dd"
        return dateformatter.string(from: Date())
    }
    // 判断文字是否为空
    func isTextEmpty(text:String) -> Bool{
        if text == "" {
            return true
        } else {
            return false
        }
    }

image.png

判断内容是否为空的方法是传入一个参数值,通过判断是否为空,从而返回一个Bool类型的值,后面我们用来判断输入的标题和内容是否为空。

App使用

创建好ViewModel后,当我们要使用它,需要在IdeaNoteApp项目页面声明好使用的ViewModel,如下代码所示:

import SwiftUI
@main
struct IdeaNoteApp: App {
    @StateObject  var viewModel: ViewModel = ViewModel()
    var body: some Scene {
        WindowGroup {
            ContentView()
                .environmentObject(viewModel)
        }
    }
}

image.png

IdeaNoteApp页面是整个App启动时的页面,它相当于我们的主函数,当前项目指向的首页是ContentView首页视图,因此在使用MVVM项目开发模式时,当我们用使用到ViewModel时,就需要引用ViewModel到主函数中方可使用。

本章小结

恭喜你,准备工作已经就绪,随时可以开始下一步的内容。

当然,为了让大家更好地吸收学习内容,本章我们就分享了如何完成Model、View Model部分,下一章节中,我们将继续完成View视图的相关内容,我们将在原来View视图的基础上进行内容调整,方便大家更好地理解SwiftUI的运作模式。

快来动手试试吧~

相关文章
|
1月前
|
人工智能 自然语言处理 前端开发
用通义灵码,从 0 开始打造一个完整APP,无需编程经验就可以完成
通义灵码携手科技博主@玺哥超carry 打造全网第一个完整的、面向普通人的自然语言编程教程。完全使用 AI,再配合简单易懂的方法,只要你会打字,就能真正做出一个完整的应用。本教程完全免费,而且为大家准备了 100 个降噪蓝牙耳机,送给前 100 个完成的粉丝。获奖的方式非常简单,只要你跟着教程完成第一课的内容就能获得。
10842 16
|
25天前
|
API Android开发 iOS开发
深入探索Android与iOS的多线程编程差异
在移动应用开发领域,多线程编程是提高应用性能和响应性的关键。本文将对比分析Android和iOS两大平台在多线程处理上的不同实现机制,探讨它们各自的优势与局限性,并通过实例展示如何在这两个平台上进行有效的多线程编程。通过深入了解这些差异,开发者可以更好地选择适合自己项目需求的技术和策略,从而优化应用的性能和用户体验。
|
1月前
|
监控 算法 iOS开发
深入探索iOS函数调用栈:符号化与性能调优实战
在iOS开发中,理解函数调用栈对于性能调优和问题排查至关重要。函数调用栈记录了程序执行过程中的函数调用顺序,通过分析调用栈,我们可以识别性能瓶颈和潜在的代码问题。本文将分享iOS函数调用栈的基本概念、符号化过程以及如何利用调用栈进行性能调优。
38 2
|
3月前
|
Web App开发 Java 视频直播
FFmpeg开发笔记(四十九)助您在毕业设计中脱颖而出的几个流行APP
对于软件、计算机等专业的毕业生,毕业设计需实现实用软件或APP。新颖的设计应结合最新技术,如5G时代的音视频技术。示例包括: 1. **短视频分享APP**: 集成FFmpeg实现视频剪辑功能,如添加字幕、转场特效等。 2. **电商购物APP**: 具备直播带货功能,使用RTMP/SRT协议支持流畅直播体验。 3. **同城生活APP**: 引入WebRTC技术实现可信的视频通话功能。这些应用不仅实用,还能展示开发者紧跟技术潮流的能力。
97 4
FFmpeg开发笔记(四十九)助您在毕业设计中脱颖而出的几个流行APP
|
3月前
|
Swift iOS开发 UED
揭秘一款iOS应用中令人惊叹的自定义动画效果,带你领略编程艺术的魅力所在!
【9月更文挑战第5天】本文通过具体案例介绍如何在iOS应用中使用Swift与UIKit实现自定义按钮动画,当用户点击按钮时,按钮将从圆形变为椭圆形并从蓝色渐变到绿色,释放后恢复原状。文中详细展示了代码实现过程及动画平滑过渡的技巧,帮助读者提升应用的视觉体验与特色。
70 11
|
4月前
|
Web App开发 Android开发
FFmpeg开发笔记(四十六)利用SRT协议构建手机APP的直播Demo
实时数据传输在互联网中至关重要,不仅支持即时通讯如QQ、微信的文字与图片传输,还包括音视频通信。一对一通信常采用WebRTC技术,如《Android Studio开发实战》中的App集成示例;而一对多的在线直播则需部署独立的流媒体服务器,使用如SRT等协议。SRT因其优越的直播质量正逐渐成为主流。本文档概述了SRT协议的使用,包括通过OBS Studio和SRT Streamer进行SRT直播推流的方法,并展示了推流与拉流的成功实例。更多细节参见《FFmpeg开发实战》一书。
79 1
FFmpeg开发笔记(四十六)利用SRT协议构建手机APP的直播Demo
|
4月前
|
Swift iOS开发 UED
【绝妙创意】颠覆你的视觉体验!揭秘一款iOS应用中令人惊叹的自定义动画效果,带你领略编程艺术的魅力所在!
【8月更文挑战第13天】本文通过一个具体案例,介绍如何使用Swift与UIKit在iOS应用中创建独特的按钮动画效果。当按钮被按下时,其形状从圆形变化为椭圆形,颜色则从蓝色渐变为绿色;释放后,动画反向恢复原状。利用UIView动画方法及弹簧动画效果,实现了平滑自然的过渡。通过调整参数,开发者可以进一步优化动画体验,增强应用的互动性和视觉吸引力。
60 7
|
4月前
|
安全 测试技术 调度
iOS开发-多线程编程
【8月更文挑战第12天】在iOS开发中,属性的内存管理至关重要,直接影响应用性能与稳定性。主要策略包括:`strong`(强引用),保持对象不被释放;`weak`(弱引用),不保持对象,有助于避免循环引用;`assign`(赋值),适用于基本数据类型及非指针对象类型;`copy`(复制),复制对象而非引用,确保不变性。内存管理基于引用计数,利用自动引用计数(ARC)自动管理对象生命周期。此外,需注意避免循环引用,特别是在block中。最佳实践包括理解各策略、避免不必要的强引用、及时释放不再使用的对象、注意block中的内存管理,并使用工具进行内存分析。正确管理内存能显著提升应用质量。
|
4月前
|
JSON 搜索推荐 定位技术
打造个性化天气应用:iOS开发实战
【8月更文挑战第31天】在这篇文章中,我们将一起探索如何从零开始构建一个iOS天气应用。通过简单易懂的步骤,你将学习到如何使用Swift编程语言和苹果的开发工具Xcode来实现这个目标。我们会涉及到用户界面设计、网络编程以及数据解析等关键技能,确保你能够顺利地完成这个项目。无论你是初学者还是有一定经验的开发者,这篇文章都会带给你新的启发和收获。
|
1月前
|
开发框架 前端开发 Android开发
安卓与iOS开发中的跨平台策略
在移动应用开发的战场上,安卓和iOS两大阵营各据一方。随着技术的演进,跨平台开发框架成为开发者的新宠,旨在实现一次编码、多平台部署的梦想。本文将探讨跨平台开发的优势与挑战,并分享实用的开发技巧,帮助开发者在安卓和iOS的世界中游刃有余。