macOS 应用开发小集锦

开发小集锦

记录开发中的琐碎技巧,以备查阅.

NumberFormatter

  • 将数字转为文字描述
 let formatter = NumberFormatter()
 formatter.numberStyle = .spellOut
 guard let words = formatter.string(from: 12320) else{ return }
 print("words = \(words)")
//结果: words = 一万二千三百二十

输出结果与当前app的语言环境有关(默认为English),如果需要修改工程的语言环境,需要设置Edit Scheme...

设置工程默认语言环境

weak 与 unowned

swift的闭包中我们在使用self时为了避免循环引用的问题,经常使用weak self 或者unowned self,这两种方式既相似又略有区别

  • [weak self]在闭包中的 self可选类型
HttpTool.request("your-url").complete{ [weak self] response in
 self?.mode = response.data
self?.updateUI()
}
  • [unowned self]在闭包中的self非可选类型: 因此若闭包执行前self被释放,会造成crash
HttpTool.request("your-url").complete{ [unowned self] response in
 self.mode = response.data
self.updateUI()
}
  • 推荐用法:
HttpTool.request("your-url").complete{ [weak self] response in
 guard let strongSelf = self else {return}
 self.mode = response.data
 self.updateUI()
}

NSBezierPath 转 CGPath

extension NSBezierPath {
    public var cgPath: CGPath {
        let path = CGMutablePath()
        var points = [CGPoint](repeating: .zero, count: 3)
        
        for i in 0 ..< self.elementCount {
            let type = self.element(at: i, associatedPoints: &points)
            switch type {
            case .moveToBezierPathElement:
                path.move(to: points[0])
            case .lineToBezierPathElement:
                path.addLine(to: points[0])
            case .curveToBezierPathElement:
                path.addCurve(to: points[2], control1: points[0], control2: points[1])
            case .closePathBezierPathElement:
                path.closeSubpath()
            }
        }
        
        return path
    }
}

获取你的公网IP地址

设置请求header后发送请求到http://ifconfig.me/ip,获取结果即可~(是不是很easy ^ _ ^ )

示例代码:

let headers: HTTPHeaders = [
      "User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/604.5.6 (KHTML, like Gecko) Version/11.0.3 Safari/604.5.6"
        ]
Alamofire.request("http://ifconfig.me/ip",headers:headers).responseString { (response) in
            print(response.result.value ?? "error")
        }

字符串插入分隔符与分隔词

var des = "Version"
let startIndex = des.startIndex
des.insert("-", at: des.index(startIndex, offsetBy: 4))    // 插入单个字母符号
des.insert(contentsOf: "hello", at: des.index(startIndex, offsetBy: 5))  // 插入多字符
print(des)  // 结果为Vers-helloion

文本朗读(iOS通用)

语音朗读

NSSpeechSynthesizer类提供了将文字转为语音的功能

 let speach = NSSpeechSynthesizer()
 speach.startSpeaking("Hello world")    // 开始朗读
  • 获取系统支持的朗读声音
for voiceName in NSSpeechSynthesizer.availableVoices {
       print(voiceName)
 }
// 输出结果
// VoiceName(_rawValue: com.apple.speech.synthesis.voice.Alex)
// VoiceName(_rawValue: com.apple.speech.synthesis.voice.alice)
// VoiceName(_rawValue: com.apple.speech.synthesis.voice.alva)
......
  • 设置朗读声音
let speach = NSSpeechSynthesizer()
let result = speach.setVoice(NSSpeechSynthesizer.VoiceName.init(rawValue: "com.apple.speech.synthesis.voice.damayanti"))
  if result {
      print("success")
  }else{
      print("failure")
  }
  • 监听朗读事件
    设置代理
let speach = NSSpeechSynthesizer()
speach.delegate = self

实现相应的代理方法,监听事件回调

func speechSynthesizer(_ sender: NSSpeechSynthesizer, willSpeakWord characterRange: NSRange, of string: String) {
        print("will speaKWord \(string) \(characterRange)")
    }
func speechSynthesizer(_ sender: NSSpeechSynthesizer, willSpeakPhoneme phonemeOpcode: Int16) {
        print("will speakPhoneme \(phonemeOpcode)")
    }
func speechSynthesizer(_ sender: NSSpeechSynthesizer, didEncounterSyncMessage message: String) {
        print("did encounter message \(message)")
    }
func speechSynthesizer(_ sender: NSSpeechSynthesizer, didFinishSpeaking finishedSpeaking: Bool) {
        print("did finishedSpeaking ")
    }
func speechSynthesizer(_ sender: NSSpeechSynthesizer, didEncounterErrorAt characterIndex: Int, of string: String, message: String) {
        print("did error \(string)")
    }

添加系统提醒事件(iOS通用)

提醒事项

使用EKEventStoreEKReminder实现添加事件到系统的提醒应用

class ViewController: NSViewController {
  fileprivate let eventStore = EKEventStore()    // 建议使用单利模式
  fileprivate  var isAuthor = false     // 检测是否进行授权
  ... ... 
}

extension ViewController{
    fileprivate func remindme(){     
        // 获取系统的授权状态
        let authorStatus = EKEventStore.authorizationStatus(for: EKEntityType.reminder)
       // 判断授权结果     
        switch authorStatus {
        case .authorized:   // 已授权,设置授权结果为true
            isAuthor = true
        case .notDetermined:   // 尚未授权,进行授权请求(回调在子线程,若处理UI,需要切到主线程)
            eventStore.requestAccess(to: .reminder, completion: { [weak self] (granted, error) in
                guard let strongSelf = self else {return}
                if granted {
                    DispatchQueue.main.async {
                        strongSelf.isAuthor = granted
                        strongSelf.createRemind()
                    }
                }
            })
        case .denied,.restricted:  // 用户拒绝授权
            print("user deny ")
        }
        
        if !isAuthor {return}
        createRemind()
    }
    
    // 创建提醒
    fileprivate func createRemind(){
       
        let reminder = EKReminder(eventStore: eventStore)   // 创建提醒器
        reminder.calendar = eventStore.defaultCalendarForNewReminders() // 设置新提醒  
        reminder.title = "remide title"      // 设置提醒事件的标题
        let alarmDate = Date(timeInterval: 15, since: Date())   // 设置提醒时间:本例为15秒后
        let alarm = EKAlarm(absoluteDate: alarmDate)    // 创建提醒
        reminder.addAlarm(alarm)          // 添加提醒到提醒器中
        do {
            try  eventStore.save(reminder, commit: true)       // 添加事件到系统提醒应用
        } catch  {
            print("save failure: \(error.localizedDescription)")
        }
    }
}

推荐阅读更多精彩内容

  • 参考资源《swifter》https://github.com/iOS-Swift-Developers/Swif...
    柯浩然阅读 832评论 0 6
  • 少年得志,是每个人都渴盼的,毕竟人生在世也就几十个寒暑,而少年岁月又十分短暂,故而,一个人能少年得志,那是十分难得...
    锡安之光阅读 44评论 0 0
  • 爸爸深沉的爱一直都在 在我成长的路上,有一样东西一直都在,那就是爸爸温暖的大手。 在小的时候,我很讨厌穿拖鞋,所以...
    天使太美丽阅读 198评论 0 2
  • 心理学是一门非常奇怪的学科。为什么这么说呢?因为它可谓是最熟悉的陌生人。生而为人,我们最伟大的成就就是我们的心理,...
    散翎阅读 86评论 0 1
  • 自由,在我的人生字典中,它是最重要的,但是太多的人放弃了这个词,束缚在一系列的规则中,最后问一下自己“...
    元宵丸子阅读 576评论 3 1