Edited at

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

俺得なので誰の参考にもならない

swift書いてて毎度書き方を忘れたり仕様を忘れたり存在自体を忘れたりしてるやつらのまとめ


PanGestureの方向


pan+extension.swift

enum PanDirection{

case up
case down
case left
case right
}

extension UIPanGestureRecognizer{
func getPanDirection(inView:UIView)->PanDirection{
let velocity = self.velocity(in: inView)
return fabs(velocity.y) > fabs(velocity.x) ?
(velocity.y > 0 ? .up : .down) :
(velocity.x > 0 ? .right : .left)
}
}



自作オペレータ

参考

// これはオペレータですよと定義

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 "かきくけこ" がランダムで


配列から毎回違う要素をランダムで選択

let arr = ["あいうえお", "かきくけこ", "さしすせそ"]

var selectedStrInArr:String=""
selectedStrInArr = arr.filter({$0 != selectedStrInArr}).shuffled().first


結合

  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が変わる


ユニークにする

extension Array where Element: Equatable {

var unique: [Element] {
return reduce([Element](), { (result, sequence) in
result.contains(sequence) ? result : result + [sequence]
})
}
}


String


String -> Int

let _ = Int("12") // -> 12

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


指定の文字列の数を数える

参考

extension String {

func numberOfOccurrences(of word: String) -> Int {
var count = 0
var nextRange = self.startIndex..<self.endIndex
while let range = self.range(of: word, options: .caseInsensitive, range: nextRange) {
count += 1
nextRange = range.upperBound..<self.endIndex
}
return count
}
}

//改行コードの数を数えてみる
let a = "あいうえお\nかきく\nけこ"
let c = a.numberOfOccurrences(of: "\n") // 2


指定した長さと文字のランダム文字列を生成

//charactersの中の文字からランダムに選ばれる

func randomString(length: Int, characters:String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") -> String {
return Array(1...length).reduce(into: "", { (str, _) in
return str.append(characters.randomElement()!)
})
}


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


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)


ふたつの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)