[Swift] GCD関連 [Swift4対応]

  • キューの作成

(Swift2まで)

let queue1 = dispatch_queue_create("arrayQ", DISPATCH_QUEUE_SERIAL)
let queue2 = dispatch_queue_create("arrayQ", DISPATCH_QUEUE_CONCURRENT)

(Swift3以降)

let queue1 = DispatchQueue(label: "arrayQ")
let queue2= DispatchQueue(label: "arrayQ", attributes: .concurrent)

(Swift2まで)

let queue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)
let queue4 = dispatch_get_main_queue()

(Swift3以降)

let queue3 = DispatchQueue.global(qos:DispatchQoS.QoSClass.background)
let queue4= DispatchQueue.main

  • グループの作成

(Swift2まで)

let group = dispatch_group_create()

(Swift3以降)

let group = DispatchGroup()

  • グループのwait

(Swift2まで)

dispatch_group_wait(group, dispatch_time_t(DISPATCH_TIME_FOREVER))

(Swift3以降)

group.wait(wallTimeout: .distantFuture)

  • 同期処理

(Swift2まで)

dispatch_sync(queue, {() in
...
}

(Swift3以降)

queue.sync {() in
...
}

  • 非同期処理

(Swift2まで)

dispatch_async(queue, {() in
...
}

(Swift3以降)

queue.async {() in
...
}

(Swift2まで)

dispatch_barrier_async(queue, {() in
...
}

(Swift3以降)

queue.async(flags: .barrier) {() in
...
}

  • セマフォ宣言

(Swift2まで)

let semaphore:dispatch_semaphore_t

(Swift3以降)

let semaphore:DispatchSemaphore

  • セマフォの作成

(Swift2まで)

semaphore = dispatch_semaphore_create(Int)

(Swift3以降)

semaphore = DispatchSemaphore(value: Int)

  • セマフォのwait

(Swift2まで)

if (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) == 0) {
...
}

(Swift3以降)

if (semaphore.wait(timeout:.distantFuture) == .success) {
...
}

  • セマフォのsignal

(Swift2まで)

dispatch_semaphore_signal(semaphore)

(Swift3以降)

semaphore.signal()

[Swift][Error]Argument labels ‘(_:)’ do not match any available overloads

・エラーメッセージ
Argument labels ‘(_:)’ do not match any available overloads

・エラー例

let num = 3
var nsnum = NSNumber(num)
// => Argument labels ‘(_:)’ do not match any available overloads

・原因
メソッドに必要なラベルが存在しないために発生します

・対策
ラベルなしで実行可能なメソッドも多いですが必要なメソッドもあるので、ドキュメントを見ながら適切に設定しましょう。

let num = 3
var nsnum = NSNumber(value: num)

Macのsedで改行を出力する

Macのsedで特定の文字を改行に変換したいと思ったことがあると思いますが、Macでは ‘\n’ が出力できません。

$ echo "pen#apple#pen#pineapple" | sed 's/#/\n/g'
pennapplenpennpineapple

こんな感じのことをすれば出力できるようなのですが面倒です。

ってことで、

$ echo "pen#apple#pen#pineapple" | sed 's/#/\
> /g'
pen
apple
pen
pineapple

てな感じで、一旦「\」を入力した後で実際に改行し、その後続けて入力すると改行が実際に出力されます。

[Swift] Swift3で対象範囲を指定して配列内の要素を削除する

ArrayクラスのremoveSubrangeメソッドを使うと以下のように削除することが出来ます。

var t = [“zero”, “one”, “two”, “three”, “four”]
t.removeSubrange(1…2)
print(t)
// => [“zero”, “three”, “four”]

[Swift] Swift3でArrayにremoveObjectを実装する

NSArrayにはremoveObjectというインデックスではなくオブジェクトを指定して配列内の該当する要素を削除するメソッドがあります。

同じものがSwiftのArrayにもあるかと思ったのですが無く困ってましたが、以下のようにextensionを使ってArrayを拡張すれば対応可能になります。

extension Array where Element: Equatable {
    // 先頭のオブジェクトのみ削除
    mutating func remove(firstObject: Element) {
        if let index = index(of: firstObject) {
            remove(at: index)
        }
    }

    // すべてのオブジェクトを削除
    mutating func remove(object: Element) {
        if let index = index(of: object){
            self.remove(at: index)
            self.remove(object: object)
        }
    }
}

これをファイルの先頭に書いておくと、以下の様にArrayを拡張してオブジェクトを指定して配列内の要素を削除することが出来ます。

var test = Array<String>()
test=[“apple”, “orange”, “Orange”, “apple”]

test.remove(firstObject: “apple”)
// => [“orange”, “Orange”, “apple”]
// 先頭のappleのみ削除され、2つ目以降のappleは削除されない。

test.remove(object: “apple”)
// => [“orange”, “Orange”]
// すべてのappleが削除される。

[Swift][Error] Value of type ‘[*]’ has no member ‘*’

・エラーメッセージ
Value of type ‘[]’ has no member ‘

・エラー例

var x:[Int] = [1,2,3]
if x.containsObject(2) {
 print(“x contains 2”)
}
// => Value of type ‘[Int]’ has no member ‘containsObject’

・原因
存在しないメソッドや変数を利用しようとした場合に発生する。

・対策
NSArrayをArrayに書き換えた場合など、つい同じ名前のメソッドが存在すると思いがちだがメソッド名変わっていたりするので、マニュアルを確認して適切に変更する。

var x:[Int] = [1,2,3]
if x.contains(2) {
 print(“x contains 2”)
}

[Swift][Error] Cannot assign value of type ‘[AnyObject]’ to type *

・エラーメッセージ
Cannot assign value of type ‘[AnyObject]’ to type *

・エラー例

var x:[Int]
var y:[AnyObject] = [1,2,3]
x = y
// => Cannot assign value of type ‘[AnyObject]’ to type ‘[Int]’

・原因
上記の場合、AnyObject型のコレクション(配列や辞書)をInt型のコレクションに格納しようとしたため

・対策
代入前に as! を使ってダウンキャストを行う

var x:[Int]
var y:[AnyObject] = [1,2,3]
x = y as! [Int]

[Swift][Error] Can’t convert value of type * to expected argument type *

・エラーメッセージ
Can’t convert value of type * to expected argument type *

・エラー例

var y:Double
var x:Int = 10
y = 10 + x
// => Can’t convert value of type ‘Int’ to expected argument type ‘Double’

・原因
上記の場合、Double型の変数にInt型の数値を格納しようとしたため

・対策
代入前に型の変換を行う

var y:Double
var x:Int = 10
y = Double(10 + x)

[Swift] インスタンスを比較する

Swiftでインスタンスの内容を比較する場合、比較したいクラスにはisEqualメソッドを実装します。

import Foundation

class TestObject : NSObject {
    var cnt:Int = 0

    override func isEqual(object: AnyObject?) -> Bool {
        if let val = object as? TestObject {
            return (self.cnt==val.cnt)
        }
        else{
            return false
        }
    }
}

この“isEqual”メソッドは“==” でインスタンス同士を比較した場合に呼び出され、インスタンスの内容が同じであればtrueを、異なっていればfalseを返すように実装します。
では、確認してみましょう。

var obj1 = TestObject()
var obj2 = TestObject()
var obj3 = TestObject()
var obj4 = TestObject()

obj1.cnt = 10
obj2.cnt = 10
obj3.cnt = 20

print(“With ‘==’ operator”)

print(obj1==obj2)
// => true ( cntの値が同じであるためtrueになる )

print(obj1==obj3)
// => false ( cntの値が異なるためfalseになる )

print(obj1==obj4)
// => true ( 参照先が同じであるため、当然trueになる )

また、“===” という演算子もありますが、こちらは左右のインスタンスの参照先が同じかどうかを確認するためのもので、内容までは比較しません。

print(“With ‘===’ operator”)

print(obj1===obj2)
// => false ( 参照先が異なるインスタンスであるためfalse )

print(obj1===obj3)
// => false ( 参照先が異なるインスタンスであるためfalse )

print(obj1===obj4)
// => true ( 同じ参照先を示すインスタンスであるためtrue )

[Swift] 文字列リテラル内で変数や定数を使うには

文字列リテラル内で変数や定数を使うには次のようにします。

let y=2016
let m=7
var d=4
var a=”月”

print(“今日は \(y)年\(m)月\(d)日 \(a)曜日 です”)
// => “今日は 2016年7月4日 月曜日 です”

“文字列\(変数・定数)文字列”
というように、\(変数・定数)と記述することで、文字列リテラル内で変数や定数を使うことができます。