| ページ一覧 | ブログ | twitter |  書式 | 書式(表) |

MyMemoWiki

「Swift Sample」の版間の差分

提供: MyMemoWiki
ナビゲーションに移動 検索に移動
169行目: 169行目:
 
</pre>
 
</pre>
 
===非同期処理===
 
===非同期処理===
 +
----
 
<pre>
 
<pre>
 
let c = {
 
let c = {

2021年5月2日 (日) 03:03時点における版

| Swift | SwiftUI |Xcode | Mac |

Swift Sample

Network

データ取得


  1. let url = URL(string: "https://www.typea.info/blog/")!
  2. let task = URLSession.shared.dataTask(with: url) { data, response, error in
  3. if let error = error {
  4. print("\(error)\n")
  5. return
  6. }
  7. guard let data = data, let response = response as? HTTPURLResponse else {
  8. print("no data or no response.")
  9. return
  10. }
  11. if response.statusCode == 200 {
  12. if let text = String(bytes: data, encoding: .utf8) {
  13. print(text)
  14. }
  15. }
  16. }
  17. task.resume()

MacOSでエラーの場合

Error Domain=NSURLErrorDomain Code=-1003

Swift macos net error.png

File

JSONにシリアライズしてドキュメントディレクトリへ書き出し

  • データ(Codableを適用する)
  1. struct Host : Codable {
  2. var host: String = ""
  3. var ip: String = ""
  4. var macaddr: String = ""
  5. }
  • 読み込み、コレクションに追加、書き出し処理
  1. func addHostListDocument(host: WoL.Host) {
  2. let docPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
  3. let filePath = URL(fileURLWithPath: "hosts.json", relativeTo:docPath)
  4. var hostList: [WoL.Host] = []
  5. let decoder = JSONDecoder()
  6. do {
  7. let rawData = try Data(contentsOf: filePath)
  8. print(rawData)
  9. let tmpHostList = try decoder.decode([WoL.Host].self, from: rawData)
  10. for tmpHost in tmpHostList {
  11. hostList.append(tmpHost)
  12. }
  13. } catch {
  14. print(error)
  15. }
  16. hostList.append(host)
  17. let encoder = JSONEncoder()
  18. do {
  19. let line = try encoder.encode(hostList)
  20. try line.write(to: filePath)
  21. } catch {
  22. print(error)
  23. }
  24. }

Swift json encode.png

書式を指定
  1. let encoder = JSONEncoder()
  2. encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
Stringに変換
  1. let json = try encoder.encode(hosts.hosts)
  2. let jsonString = String(data: json, encoding: .utf8)!
  3. print(jsonString)
画面とオブジェクトを共有する
  • struct -> class
  • ObservableObject を適用
  • @Published
  • 上記を適用すると、Codable に適合させるには、明示的に処理を記述する必要がある
  1. class Host : Codable, ObservableObject {
  2. @Published var host: String = ""
  3. @Published var ip: String = ""
  4. @Published var macaddr: String = ""
  5. @Published var comment: String = ""
  6.  
  7. init(host: String, ip: String, macaddr: String, comment: String) {
  8. self.host = host
  9. self.ip = ip
  10. self.macaddr = macaddr
  11. self.comment = comment
  12. }
  13. init() {}
  14.  
  15. /// 変換対象プロパティ
  16. enum CodingKeys: CodingKey {
  17. case host
  18. case ip
  19. case macaddr
  20. case comment
  21. }
  22.  
  23. required init(from decoder: Decoder) throws {
  24. let container = try decoder.container(keyedBy: CodingKeys.self)
  25. host = try container.decode(String.self, forKey: .host)
  26. ip = try container.decode(String.self, forKey: .ip)
  27. macaddr = try container.decode(String.self, forKey: .macaddr)
  28. comment = try container.decode(String.self, forKey: .comment)
  29. }
  30.  
  31. func encode(to encoder: Encoder) throws {
  32. var container = encoder.container(keyedBy: CodingKeys.self)
  33. try container.encode(host, forKey: .host)
  34. try container.encode(ip, forKey: .ip)
  35. try container.encode(macaddr, forKey: .macaddr)
  36. try container.encode(comment, forKey: .comment)
  37. }

UI

バックグラウンドからUIを操作する


  • observableobj が、ObservableObject の派生クラス
  • contentフィールドに、@Published アノテーション
  • Viewで、@ObservedObjectを付与しインスタンスを生成
  • 上記で、バックグラウンドから、observableobj.contentを操作すると、UIはメインスレッドから触るように怒られる。

Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.

  • DispatchQueue.main.syncで囲む
  1. DispatchQueue.main.sync {
  2. observableobj.content = text
  3. }

処理

サブプロセスを起動

  • プロセスを起動し、arp -a を呼び出し、出力
  1. func arp() {
  2. let outputPipe = Pipe()
  3.  
  4. func shell(path:String ,args: String...) -> Int32 {
  5. let task = Process()
  6. task.launchPath = path
  7. task.arguments = args
  8. task.standardOutput = outputPipe
  9. task.standardError = outputPipe
  10. task.launch()
  11. task.waitUntilExit()
  12. return task.terminationStatus
  13. }
  14. let _ = shell(path:"/usr/sbin/arp",args: "-a")
  15. let theTaskData = outputPipe.fileHandleForReading.readDataToEndOfFile()
  16. let stringResult = String(data: theTaskData, encoding: .utf8)
  17. print(stringResult!)
  18. }

非同期処理


  1. let c = {
  2. (ip:String) -> String in
  3. let hostName = getHostName(ip: ip) // 時間がかかる処理
  4. return hostName
  5. }
  6.  
  7. let que = DispatchQueue.global(qos: .default)
  8. for host in hosts.hosts {
  9. print("CALL-\(host.ip)")
  10. que.async { // 非同期処理
  11. let hostname = c(host.ip) // 時間がかかる処理
  12. DispatchQueue.main.async { // 画面に反映
  13. host.host = hostname
  14. }
  15. }
  16. }

正規表現

arp -a の結果からIPアドレスを抜きだす


  1. func parseArp(arpResult: String?) {
  2. if let input = arpResult {
  3. do {
  4. let pattern = #"[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"#
  5. let regex = try NSRegularExpression(pattern: pattern, options:[])
  6. for subinput in input.split(separator: "\r\n") {
  7. let line = String(subinput)
  8. let maches = regex.matches(in: line, options: [], range: _NSRange(0..<line.count))
  9. print(line)
  10. for mach in maches {
  11. for i in 0 ..< mach.numberOfRanges {
  12. let start = line.index(line.startIndex, offsetBy: mach.range(at: i).location)
  13. let end = line.index(start, offsetBy: mach.range(at: i).length)
  14. let text = String(line[start..<end])
  15. print(text)
  16. }
  17. }
  18. }
  19. } catch {
  20. print("RegEx fail.")
  21. }
  22. } else {
  23. print("arp -a result : error")
  24. }

名前を付与してキャプチャ


  1. func parseArp(arpResult: String?) {
  2. if let input = arpResult {
  3. do {
  4. let pattern = #".*?(?<ip>[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}).*(?<mac>[0-9a-z]{1,2}:[0-9a-z]{1,2}:[0-9a-z]{1,2}:[0-9a-z]{1,2}:[0-9a-z]{1,2}:[0-9a-z]{1,2})"#
  5. let regex = try NSRegularExpression(pattern: pattern, options:[])
  6. for subinput in input.split(separator: "\r\n") {
  7. let line = String(subinput)
  8. let matches = regex.matches(in: line, options: [], range: _NSRange(0..<line.count))
  9. print(line)
  10. for match in matches {
  11. for name in ["ip", "mac"] {
  12. let matchRange = match.range(withName: name)
  13. if let substrRanget = Range(matchRange, in:line) {
  14. let ip = String(line[substrRanget])
  15. print("\(name):\(ip)")
  16. }
  17. }
  18. }
  19. }
  20. } catch {
  21. print("RegEx fail.")
  22. }
  23. } else {
  24. print("arp -a result : error")
  25. }
  26. }