创建一个可编辑的文本应用
创建工程
- 开发语言选择:swift
- UI选择:storyboards
创建好后工程结构,默认是一种MVC架构的工程模式。
- AppDelegate.swift:入口程序
- ViewController.swift:视图控制器,相当于Controller
- Document.swift:相当于Model
- Assets.xcassets:应用图标和图片资源库
- Main.storyboard:UI图形界面,相当于View
- Info.plist:应用设置
- swift2cocoa.entitlements:应用发布和运行设置
准备工作
设计UI界面
打开 Main.storyboard 文件。
拖动UI控件到设计面板上
设计视图控制器
添加一个文本和两个按钮事件
import Cocoa
class ViewController: NSViewController {
@IBOutlet var textView: NSTextView!
@IBAction func speakButtonClicked(_ sender: NSButton){
print("The speak button was clicked")
}
@IBAction func stopButtonClicked(_ sender: NSButton){
print("The stop button was clicked")
}
}
连接控件
方法有很多,主要是拖动,其中一种拖动方式如下图所示:
另一个拖动方式,把控件拖到controller上面
添加功能
语音朗读
修改Controller代码
class ViewController: NSViewController {
@IBOutlet var textView: NSTextView!
let speechSynthesizer = NSSpeechSynthesizer()
var contents:String?{
get{
return textView.string
}
set{
textView.string = newValue ?? ""
}
}
@IBAction func speakButtonClick(_ sender:NSButton){
if(!textView.string.isEmpty){
speechSyntheesizer.startSpeaking(textView.string)
}else{
speechSyntheesizer.startSpeaking("文档是空的")
}
}
@IBAction func stopButtonClicked(_ sender: NSButton){
speechSynthesizer.stopSpeaking()
}
}
文档保存
这里稍整理下代码,把M和C串起来
Controller
import Cocoa
class ViewController: NSViewController {
@IBOutlet var textView: NSTextView!
var contents: String? {
get {
return textView.string
}
set {
textView.string = newValue
}
}
let speechSynthesizer = NSSpeechSynthesizer()
@IBAction func speakButtonClicked(_ sender: NSButton){
speechSynthesizer.startSpeaking(textView.string)
}
@IBAction func stopButtonClicked(_ sender: NSButton){
speechSynthesizer.stopSpeaking()
}
}
Document
import Cocoa
class Document: NSDocument {
override init() {
super.init()
}
enum Error: Swift.Error, LocalizedError {
case UTF8Encoding
case UTF8Decoding
var failureReason: String? {
switch self {
case .UTF8Encoding: return "File cannot be encoded in UTF-8."
case .UTF8Decoding: return "File is not valid UTF-8."
}
}
}
//文本内容
var contents: String = ""
//自动保存功能
override class var autosavesInPlace: Bool {
return true
}
//创建新文档或打开旧文档时调用,负责设置NSWindowController, as!是一个类型转符,相当于强转
override func makeWindowControllers() {
let storyboard = NSStoryboard(name: NSStoryboard.Name("Main"), bundle: nil)
//因为withIdentifier会返回很多不同的controller,所以这块需要强转一下
let windowController = storyboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("Document Window Controller")) as! NSWindowController
//连接controller
let viewController = windowController.contentViewController as! ViewController
viewController.contents = contents
self.addWindowController(windowController)
}
//保存文档时调用
override func data(ofType typeName: String) throws -> Data {
let windowController = windowControllers[0]
let viewController = windowController.contentViewController as! ViewController
let contents = viewController.contents ?? ""
guard let data = contents.data(using: .utf8) else {
throw Document.Error.UTF8Encoding
}
return data
}
override func read(from data: Data, ofType typeName: String) throws {
guard let contents = String(data: data, encoding: .utf8) else {
throw Document.Error.UTF8Decoding
}
self.contents = contents
}
}