iOS
Swift

SwiftやiOSの便利だけど忘れそうな小ネタ集

俺得なので誰の参考にもならない
swift書いてて毎度書き方を忘れたり仕様を忘れたり存在自体を忘れたりしてるやつらのまとめ

Grand Central Dispatch(GCD)

参考
参考

GCDクラス

gcd.swift
class GCD{
  // 時間のかかる処理
  private static func doSomething(number: Int) {
    print("------- Task \(number): Start -------")
    for i in 0 ... 5 {
      usleep(500000)//0.5sec待ち

      print("Task \(number): Running ... \(i * 20)%")
    }
    print("------- Task \(number): Completed -------")
  }

  // すべて直列で処理
  static func inMainQueueOnly() {
    for i in 1 ... 3 {
      doSomething(number: i)
    }
    print("All tasks completed.")
  }

  // キューを並列で処理
  static func inConcurrentQueue() {
    let queue = DispatchQueue.global(qos: .default)
    for i in 1 ... 3 {
      queue.async {
        self.doSomething(number: i)
      }
    }
    print("ここはキューの処理完了を待たずに実行される")
  }

  // 複数のキューを並列処理した後に、さらに処理を行う
  static func doMoreAfterConcurretQueuesUsingDispatchGroup() {
    let group = DispatchGroup()
    let queue = DispatchQueue.global(qos: .default)

    for i in 1 ... 3 {
      group.enter()
      queue.async {
        self.doSomething(number: i)
        group.leave()
      }
    }
    group.notify(queue: DispatchQueue.global(qos: .default)) {
      print("すべてのキューの処理が完了しました")
    }
  }

  // 何か処理した後に値を返す(セマフォを使用)
  static func returnsValueAfterAQueueUsingSemaphore() -> String {
    var string = "初期値"
    let semaphore = DispatchSemaphore(value: 0)
    let queue = DispatchQueue.global(qos: .default)

    for i in 1 ... 3 {
      queue.sync {
        self.doSomething(number: i)
        string += " => Task\(i)が終了"
        semaphore.signal()
      }
    }

    for _ in 1 ... 3 {
      semaphore.wait()
    }
    return string
  }
  // キューを並列処理した後に値を返す(セマフォを使用)
  static func returnsValueAfterConcurrentQueuesUsingSemaphore() -> String {
    var string = "初期値"
    let semaphore = DispatchSemaphore(value: 0)
    let queue = DispatchQueue.global(qos: .default)
    for i in 1 ... 3 {
      queue.async {
        self.doSomething(number: i)
        string += " => Task\(i)が終了"
        semaphore.signal()
      }
    }
    for _ in 1 ... 3 {
      semaphore.wait()
    }
    return string
  }
}

直列で処理

GCD.inMainQueueOnly()

並列で処理

GCD.inConcurrentQueue()

並列処理した後に処理を実行する

GCD.doMoreAfterConcurretQueuesUsingDispatchGroup()

直列処理した後に値を返す

  let result = GCD.returnsValueAfterAQueueUsingSemaphore()
  print(result)

並列処理した後に値を返す

  let result = GCD.returnsValueAfterConcurrentQueuesUsingSemaphore()
  print(result)

自作オペレータ

参考

// これはオペレータですよと定義
infix operator =~

//そのオペレータの実装
func =~(lhs: String, rhs: String) -> Bool {
/*
何かしらの処理
*/
  return true
}

配列

初期化

参考

var intArray = [Int](repeating: 5, count: 100) //[5, 5, 5,...,5]
var strArray = [String](repeating: "hello", count: 50) //["hello", "hello",...,"hello"]
var intArray2 = Array(1...100) //[1, 2, 3, ..., 98, 99, 100]

ランダム

["あいうえお", "かきくけこ"].randomElement() // "あいうえお" or "かきくけこ" がランダムで

結合

  var a = [1,2,3,4,5]
  var b = [10,11,12,13,14,15]

  var c = a + b // [1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15] cに代入
  a.append(contentsOf: b)  //[1, 2, 3, 4, 5, 10, 11, 12, 13, 14, 15] aが変わる

  var aa = [[1,2,3],[4,5,6]]
  var bb = [[11,12,13],[14,15,16]]

  var cc = aa + bb // [[1, 2, 3], [4, 5, 6], [11, 12, 13], [14, 15, 16]] ccに代入
  aa.append(contentsOf: bb) // [[1, 2, 3], [4, 5, 6], [11, 12, 13], [14, 15, 16]] aaが変わる
  bb.append(b) //[[11, 12, 13], [14, 15, 16], [10, 11, 12, 13, 14, 15]] bbが変わる

String -> Int

let _ = Int("12") // -> 12
let _ = Int("012") // -> 12
let _ = Int("+12") // -> 12
let _ = Int("-12") // -> -12
let _ = Int("12.3") // -> nil

CGRectの操作

// 元のCGRect
let f1 = CGRect(x: 10, y: 20, width: 30, height: 40) //{x 10 y 20 w 30 h 40}

//dx,dy分、f1の中に入るCGRect (originだけがずれるわけじゃないよ)
let f2 = f1.insetBy(dx: 5, dy: 5) //{x 15 y 25 w 20 h 30}

//insetByの細かく指定できる版
let f3 = f1.inset(by: UIEdgeInsets.init(top: 5, left: 5, bottom: 10, right: 10)) //(15.0, 25.0, 15.0, 25.0)

//指定した位置でframeを分割する 
let f4 = f1.divided(atDistance: 5, from: CGRectEdge.minXEdge) //slice: (10.0, 20.0, 5.0, 40.0), remainder: (15.0, 20.0, 25.0, 40.0))

Autolayout

StackView in CollcectionViewCell

CollectionViewCellの中にStackViewを入れるときはひとつViewを挟む
セルの高さの制約はpriorityを750にしとく

Screenshot from Gyazo

その他

ふたつのTableViewのスクロールを同期させる

RxSwiftありきの実装

    tableView1.rx.didScroll.asObservable()
      .filter({(_) -> Bool in
        self.tableView2.contentOffset.y != self.tableView1.contentOffset.y
      })
      .subscribe(onNext: {[weak self] (_) in
        guard let wSelf = self else{return}
        let x = wSelf.tableView2.contentOffset.x
        let y = wSelf.tableView1.contentOffset.y
        wSelf.tableView2.setContentOffset(CGPoint(x:x, y:y), animated: false)
    }).disposed(by: disposeBag)

    tableView2.rx.didScroll.asObservable()
      .filter({ (_) -> Bool in
        self.tableView2.contentOffset.y != self.tableView1.contentOffset.y
      })
      .subscribe(onNext: {[weak self] (_) in
        guard let wSelf = self else{return}
        let x = wSelf.tableView1.contentOffset.x
        let y = wSelf.tableView2.contentOffset.y
        wSelf.tableView1.setContentOffset(CGPoint(x:x, y:y), animated: false)
    }).disposed(by: disposeBag)