Swift, Objective-C'nin “senkronize” si ile eşdeğerdir?


231

Swift kitabını aradım, ancak @synchronized'in Swift sürümünü bulamıyorum. Swift'te karşılıklı dışlamayı nasıl yaparım?


1
Bir sevkiyat bariyeri kullanırdım. Engeller çok ucuz senkronizasyon sağlar. dispatch_barrier_async (). vs.
Frederick C. Lee

@ FrederickC.Lee, senkronize edilecek bir yazmaya ihtiyacınız varsa , örneğin bir sarmalayıcı oluştururken removeFirst()?
ScottyBlades

Yanıtlar:


183

GCD kullanabilirsiniz. Bundan biraz daha ayrıntılı @synchronized, ancak bir yedek olarak çalışıyor:

let serialQueue = DispatchQueue(label: "com.test.mySerialQueue")
serialQueue.sync {
    // code
}

12
Bu harika, ancak synchronized ile olan yeniden giriş yeteneğinden yoksun.
Michael Waterfall

9
Bu yaklaşımla dikkatli olmalısınız. Bloğunuz başka bir iş parçacığında yürütülebilir. API belgeleri şunları söylüyor: "Bir optimizasyon olarak, bu işlev mümkün olduğunda geçerli iş parçacığındaki bloğu çağırır."
bio

20
Matt Gallagher'dan bu konuda harika bir makale: cocoawithlove.com/blog/2016/06/02/threads-and-mutexes.html
wuf810

4
Hayır, bu ara sıra kilitlenmelere neden olur.
Tom Kraina

70
Hayır, hayır ve hayır. Güzel deneyin, ama kusurlu iyi çalışıyor. Neden? Temel okuma (alternatiflerin, uyarıların kapsamlı bir şekilde karşılaştırılması) ve Matt Gallagher'ın harika bir yardımcı çerçevesi, burada: cocoawithlove.com/blog/2016/06/02/threads-and-mutexes.html @ wuf810 bu ilkinden (HT) bahsetti, ancak bu makalelerin ne kadar iyi olduğunun altını çizdi. Herkes okumalı. (Lütfen başlangıçta görünür olmasını sağlamak için minimum düzeyde oy verin, ancak daha fazla değil.)
t0rst

181

Bunu kendim arıyordum ve henüz bunun için hızlı bir iç yapı yok.

Matt Bridges ve diğerlerinden gördüğüm bazı kodlara dayanarak bu küçük yardımcı işlevi yaptım.

func synced(_ lock: Any, closure: () -> ()) {
    objc_sync_enter(lock)
    closure()
    objc_sync_exit(lock)
}

Kullanımı oldukça basit

synced(self) {
    println("This is a synchronized closure")
}

Bununla ilgili bulduğum bir sorun var. Bir diziyi kilit argümanı olarak iletmek, bu noktada çok geniş bir derleyici hatasına neden oluyor gibi görünüyor. Aksi halde istendiği gibi çalışıyor gibi görünüyor.

Bitcast requires both operands to be pointer or neither
  %26 = bitcast i64 %25 to %objc_object*, !dbg !378
LLVM ERROR: Broken function found, compilation aborted!

Güzel! 1.0 için hala sorun varsa bunun için bir hata dosyası
MattD

14
Bu oldukça yararlıdır ve sözdizimini koruyan @synchronizedgüzel bloğu, ama not o gibi gerçek yerleşik blok deyimi ile aynı olmadığını @synchronized, çünkü Objective-C blok returnve breakbenzeri çevreleyen fonksiyonu / döngü atlamaya artık çalışmaz ifadeleri bu sıradan bir ifade olsaydı olurdu.
newacct

3
Hata, dizilerin referans değil değerler olarak iletilmesinden kaynaklanıyor
james_alvarez

9
Bu muhtemelen atar bile çağrılmasını defersağlamak için yeni anahtar kelime kullanmak için harika bir yer olurdu . objc_sync_exitclosure
devios1

3
@ t0rst Bu cevaba bağlantı verilen makaleye göre "hatalı" olarak adlandırmak geçerli değil. Makale, bu yöntemin "idealden biraz daha yavaş" olduğunu ve "Apple platformlarıyla sınırlı olduğunu" söylüyor. Bu onu uzun bir atışla "kusurlu" yapmaz.
RenniePet

150

Buradaki cevapların çoğunu seviyorum ve kullanıyorum, bu yüzden sizin için en uygun olanı seçerim. Bununla birlikte, obj-c gibi bir şeye ihtiyacım olduğunda tercih ettiğim yöntem , hızlı 2'de sunulan ifadeyi @synchronizedkullanır defer.

{ 
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }

    //
    // code of critical section goes here
    //

} // <-- lock released when this block is exited

Bu yöntem hakkında güzel bir şey, kritik bölüm istenilen herhangi bir şekilde içeren blok çıkabilirsiniz olmasıdır (örneğin return, break, continue, throw) ve "erteleme ifadesi içinde ifadeleri program kontrol aktarılır nasıl olursa olsun yürütülür." 1


Bence bu muhtemelen burada sunulan en şık çözüm. Geri bildiriminiz için teşekkürler.
Scott D

3
Nedir lock? Nasıl lockbaşlatılır?
Van Du Tran

6
lockherhangi bir objektif-c nesnesidir.
ɳeuroburɳ

1
Mükemmel! Swift 1 tanıtıldığında bazı kilit yardımcı yöntemleri yazmıştım ve bir süre sonra bunları tekrar gözden geçirmemiştim. Ertelemeyi tamamen unuttum; bu yol!
Randy

Bu gibi ama bir derleyici hatası almak Xcode 8 "deyimleri Braced bloğu kullanılmayan bir kapanış olduğunu" Ah olsun onlar sadece fonksiyon parantez vardır - "1" referans linki bulmak için bir süre - teşekkürler!
Duncan Groenewald

83

Sen arasındaki ifadeleri sandviç olabilir objc_sync_enter(obj: AnyObject?)ve objc_sync_exit(obj: AnyObject?). @Synchronized anahtar sözcüğü kapakların altındaki bu yöntemleri kullanıyor. yani

objc_sync_enter(self)
... synchronized code ...
objc_sync_exit(self)

3
Bu, Apple tarafından özel bir API kullanımı olarak kabul edilecek mi?
Drux

2
Hayır objc_sync_enterve objc_sync_exitObjc-sync.h dosyasında tanımlanan ve açık kaynak yöntemlerdir: opensource.apple.com/source/objc4/objc4-371.2/runtime/…
bontoJR

Birden çok iş parçacığı aynı kaynağa erişmeye çalışırsa, ikincisi bekler, yeniden dener veya çöker?
TruMan1

@BontoJR söylediklerini üzerine ekleme objc_sync_enter(…)ve objc_sync_exit(…)vb iOS / MacOS / sağladığı kamu başlıkları bulunmaktadır. API'lar ( ….sdkyolun içindeymiş gibi görünüyor usr/include/objc/objc-sync.h) . Bir şeyin herkese açık bir API olup olmadığını öğrenmenin en kolay yolu (Xcode'da) işlev adını yazmaktır (örneğin objc_sync_enter(); C işlevleri için bağımsız değişkenlerin belirtilmesi gerekmez) , sonra komut tıklatmayı deneyin. Bu API'nın başlık dosyasını gösterirse, iyidir (başlık herkese açık olmasaydı başlığı göremezsiniz) .
Slipp D. Thompson

75

@synchronizedObjective-C yönergesinin analogu, rethrowsSwift'te keyfi bir dönüş tipi ve hoş bir davranışa sahip olabilir.

// Swift 3
func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return try body()
}

İfadenin kullanılması, defergeçici bir değişken girmeden doğrudan bir değer döndürmenizi sağlar.


Swift 2'de, @noescapedaha fazla optimizasyona izin vermek için özelliği kapağa ekleyin :

// Swift 2
func synchronized<T>(lock: AnyObject, @noescape _ body: () throws -> T) rethrows -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return try body()
}

GNewc [1] (rasgele dönüş tipini sevdiğim) ve Tod Cunningham [2] (sevdiğim yer defer) yanıtlarına dayanarak .


Xcode @noescape'in artık varsayılan olduğunu ve Swift 3'te kullanımdan kaldırıldığını söylüyor
RenniePet

Bu doğru, bu cevaptaki kod Swift 2 için ve Swift 3 için bazı uyarlama gerektiriyor. Zamanım olduğunda bunu güncelleyeceğim.
werediver

1
Kullanımı açıklayabilir misiniz? Belki bir örnekle .. şimdiden teşekkürler! Benim durumumda, ben bir DispatchQueue içeriğini manipüle çünkü senkronize etmek gerekir bir Set var.
sancho

@sancho Bu yazıyı kısa tutmayı tercih ederim. Genel eşzamanlı programlama yönergeleri hakkında soru soruyorsunuz, bu geniş bir soru. Ayrı bir soru olarak sormaya çalışın!
werediver

41

SWIFT 4

Swift 4'te kaynakları kilitlemek için GCD dağıtım kuyruklarını kullanabilirsiniz.

class MyObject {
    private var internalState: Int = 0
    private let internalQueue: DispatchQueue = DispatchQueue(label:"LockingQueue") // Serial by default

    var state: Int {
        get {
            return internalQueue.sync { internalState }
        }

        set (newState) {
            internalQueue.sync { internalState = newState }
        }
    }
} 

Bu XCode8.1 ile çalışmıyor gibi görünüyor. .serialkullanılamıyor gibi görünüyor. Ancak .concurrentkullanılabilir. : /
Travis Griggs

2
varsayılan .serial
Duncan Groenewald

2
Bu desenin, çok yaygın olan çok iş parçacığı sorunlarına karşı düzgün bir şekilde korunmadığına dikkat edin. Örneğin, myObject.state = myObject.state + 1aynı anda çalışırsanız , toplam işlemleri saymaz, bunun yerine belirsiz olmayan bir değer verir. Bu sorunu çözmek için, arama kodu seri bir sıraya sarılmalıdır, böylece hem okuma hem de yazma atomik olarak gerçekleşir. Tabii ki Obj-c'lerin @synchronisedde aynı sorunu var, bu yüzden uygulamanız doğrudur.
Berik

1
Evet, önce myObject.state += 1okuma, sonra yazma işlemlerinin birleşimidir. Başka bir iş parçacığı hala bir değer ayarlamak / yazmak için arasına girebilir. Gereğince objc.io/blog/2018/12/18/atomic-variables , yayınlanmaya kolay olurdu setkendisi değişken altında yerine ve bir senkron blok / kapanmasında.
CyberMew

23

Dönüş işlevselliği eklemek için şunları yapabilirsiniz:

func synchronize<T>(lockObj: AnyObject!, closure: ()->T) -> T
{
  objc_sync_enter(lockObj)
  var retVal: T = closure()
  objc_sync_exit(lockObj)
  return retVal
}

Daha sonra, şunu kullanarak arayabilirsiniz:

func importantMethod(...) -> Bool {
  return synchronize(self) {
    if(feelLikeReturningTrue) { return true }
    // do other things
    if(feelLikeReturningTrueNow) { return true }
    // more things
    return whatIFeelLike ? true : false
  }
}

23

Bryan McLemore cevabını kullanarak, Swift 2.0 erteleme yeteneğiyle güvenli bir malikaneye atılan nesneleri desteklemek için uzattım.

func synchronized( lock:AnyObject, block:() throws -> Void ) rethrows
{
    objc_sync_enter(lock)
    defer {
        objc_sync_exit(lock)
    }

    try block()
}

Kullanımı daha iyi olurdu rethrowsolmayan atma kapanışları (kullanım gerek olmayan basitleştirmek kullanımına trygösterildiği gibi) Cevabıma .
werediver

10

Hızlı 3

Bu kod yeniden giriş özelliğine sahiptir ve Asenkron işlev çağrılarıyla çalışabilir. Bu kodda, someAsyncFunc () çağrıldıktan sonra, seri sıradaki başka bir işlev kapanışı işlenir ancak signal () çağrılıncaya kadar semaphore.wait () tarafından engellenir. internalQueue.sync, yanılmıyorsam ana iş parçacığını engelleyeceği için kullanılmamalıdır.

let internalQueue = DispatchQueue(label: "serialQueue")
let semaphore = DispatchSemaphore(value: 1)

internalQueue.async {

    self.semaphore.wait()

    // Critical section

    someAsyncFunc() {

        // Do some work here

        self.semaphore.signal()
    }
}

objc_sync_enter / objc_sync_exit hata işlemeden iyi bir fikir değildir.


Ne hata işleme? Derleyici fırlatan hiçbir şeye izin vermez. Öte yandan, objc_sync_enter / exit kullanmadan, bazı önemli performans kazançlarından vazgeçersiniz.
gnasher729

8

2018 WWDC'nin "Çökmeleri ve Çökme Günlüklerini Anlama" oturumunda 414 oturumunda senkronize edilmiş DispatchQueues kullanarak aşağıdaki yolu gösterirler.

Hızlı 4'te aşağıdaki gibi bir şey olmalıdır:

class ImageCache {
    private let queue = DispatchQueue(label: "sync queue")
    private var storage: [String: UIImage] = [:]
    public subscript(key: String) -> UIImage? {
        get {
          return queue.sync {
            return storage[key]
          }
        }
        set {
          queue.sync {
            storage[key] = newValue
          }
        }
    }
}

Her neyse, engelli eşzamanlı kuyrukları kullanarak daha hızlı okuma yapabilirsiniz. Senkronizasyon ve zaman uyumsuz okumalar eş zamanlı olarak gerçekleştirilir ve önceki işlemlerin tamamlanmasını yeni bir değer yazmak bekler.

class ImageCache {
    private let queue = DispatchQueue(label: "with barriers", attributes: .concurrent)
    private var storage: [String: UIImage] = [:]

    func get(_ key: String) -> UIImage? {
        return queue.sync { [weak self] in
            guard let self = self else { return nil }
            return self.storage[key]
        }
    }

    func set(_ image: UIImage, for key: String) {
        queue.async(flags: .barrier) { [weak self] in
            guard let self = self else { return }
            self.storage[key] = image
        }
    }
}

muhtemelen okumaları engellemenize ve senkronizasyonu kullanarak kuyruğu yavaşlatmanıza gerek yoktur. Senkronizasyonu sadece seri yazma için kullanabilirsiniz.
Basheer_CAD

6

Swift4'te NSLock kullanın :

let lock = NSLock()
lock.lock()
if isRunning == true {
        print("Service IS running ==> please wait")
        return
} else {
    print("Service not running")
}
isRunning = true
lock.unlock()

Uyarı NSLock sınıfı, kilitleme davranışını uygulamak için POSIX iş parçacıklarını kullanır. Bir NSLock nesnesine kilit açma mesajı gönderirken, mesajın ilk kilit mesajını gönderen aynı iş parçacığından gönderildiğinden emin olmalısınız. Farklı bir iş parçacığından bir kilidin kilidinin açılması, tanımlanmamış davranışa neden olabilir.



6

Modern Swift 5'te, geri dönüş özelliği ile:

/**
Makes sure no other thread reenters the closure before the one running has not returned
*/
@discardableResult
public func synchronized<T>(_ lock: AnyObject, closure:() -> T) -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }

    return closure()
}

Dönüş değeri özelliğinden yararlanmak için bu şekilde kullanın:

let returnedValue = synchronized(self) { 
     // Your code here
     return yourCode()
}

Ya da aksi takdirde:

synchronized(self) { 
     // Your code here
    yourCode()
}

2
Bu doğru cevaptır ve kabul edilen ve yüksek oranda onaylanan cevap değildir (buna bağlıdır GCD). Aslında hiç kimse nasıl kullanılacağını ya da nasıl kullanılacağını anlamıyor Thread. Ben bundan memnunum - oysa GCDgotchas ve sınırlamalarla doludur.
javadba

4

Deneyin: NSRecursiveLock

Bir kilitlenmeye neden olmadan aynı iş parçacığı tarafından birden çok kez alınabilen bir kilit.

let lock = NSRecursiveLock()

func f() {
    lock.lock()
    //Your Code
    lock.unlock()
}

func f2() {
    lock.lock()
    defer {
        lock.unlock()
    }
    //Your Code
}

2

Şekil Swift 5 uygulamasını önceki cevaplardan yola çıkarak yayınlayacağım. Teşekkürler beyler! Ben de bir değer döndüren bir tane için yararlı buldum, bu yüzden iki yöntem var.

İlk yapmak için basit bir sınıf:

import Foundation
class Sync {
public class func synced(_ lock: Any, closure: () -> ()) {
        objc_sync_enter(lock)
        defer { objc_sync_exit(lock) }
        closure()
    }
    public class func syncedReturn(_ lock: Any, closure: () -> (Any?)) -> Any? {
        objc_sync_enter(lock)
        defer { objc_sync_exit(lock) }
        return closure()
    }
}

Ardından, bir dönüş değerine ihtiyaç duyuyorsanız bu şekilde kullanın:

return Sync.syncedReturn(self, closure: {
    // some code here
    return "hello world"
})

Veya:

Sync.synced(self, closure: {
    // do some work synchronously
})

Deneyin public class func synced<T>(_ lock: Any, closure: () -> T), hem geçersizdir, hem de geçersizdir. Ayrıca yeniden regrows şeyler var.
hnh

@hnh regrows şeyleriyle ne demek istiyorsun? Ayrıca, cevabı güncellememe yardımcı olacak <T> türüyle genel yönteme örnek bir çağrıyı paylaşmak isterseniz, bununla nereye gittiğinizi seviyorum.
TheJeff

rethrows, değil regrows, srz
hnh

1

ayrıntılar

xCode 8.3.1, hızlı 3.1

Görev

Farklı evrelerden (async) yazma değerini okuyun.

kod

class AsyncObject<T>:CustomStringConvertible {
    private var _value: T
    public private(set) var dispatchQueueName: String

    let dispatchQueue: DispatchQueue

    init (value: T, dispatchQueueName: String) {
        _value = value
        self.dispatchQueueName = dispatchQueueName
        dispatchQueue = DispatchQueue(label: dispatchQueueName)
    }

    func setValue(with closure: @escaping (_ currentValue: T)->(T) ) {
        dispatchQueue.sync { [weak self] in
            if let _self = self {
                _self._value = closure(_self._value)
            }
        }
    }

    func getValue(with closure: @escaping (_ currentValue: T)->() ) {
        dispatchQueue.sync { [weak self] in
            if let _self = self {
                closure(_self._value)
            }
        }
    }


    var value: T {
        get {
            return dispatchQueue.sync { _value }
        }

        set (newValue) {
            dispatchQueue.sync { _value = newValue }
        }
    }

    var description: String {
        return "\(_value)"
    }
}

kullanım

print("Single read/write action")
// Use it when when you need to make single action
let obj = AsyncObject<Int>(value: 0, dispatchQueueName: "Dispatch0")
obj.value = 100
let x = obj.value
print(x)

print("Write action in block")
// Use it when when you need to make many action
obj.setValue{ (current) -> (Int) in
    let newValue = current*2
    print("previous: \(current), new: \(newValue)")
    return newValue
}

Tam Örnek

uzantı DispatchGroup

extension DispatchGroup {

    class func loop(repeatNumber: Int, action: @escaping (_ index: Int)->(), completion: @escaping ()->()) {
        let group = DispatchGroup()
        for index in 0...repeatNumber {
            group.enter()
            DispatchQueue.global(qos: .utility).async {
                action(index)
                group.leave()
            }
        }

        group.notify(queue: DispatchQueue.global(qos: .userInitiated)) {
            completion()
        }
    }
}

sınıf ViewController

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        //sample1()
        sample2()
    }

    func sample1() {
        print("=================================================\nsample with variable")

        let obj = AsyncObject<Int>(value: 0, dispatchQueueName: "Dispatch1")

        DispatchGroup.loop(repeatNumber: 5, action: { index in
            obj.value = index
        }) {
            print("\(obj.value)")
        }
    }

    func sample2() {
        print("\n=================================================\nsample with array")
        let arr = AsyncObject<[Int]>(value: [], dispatchQueueName: "Dispatch2")
        DispatchGroup.loop(repeatNumber: 15, action: { index in
            arr.setValue{ (current) -> ([Int]) in
                var array = current
                array.append(index*index)
                print("index: \(index), value \(array[array.count-1])")
                return array
            }
        }) {
            print("\(arr.value)")
        }
    }
}

1

Swift'in mülk sarmalayıcıları ile şu an kullandığım şey:

@propertyWrapper public struct NCCSerialized<Wrapped> {
    private let queue = DispatchQueue(label: "com.nuclearcyborg.NCCSerialized_\(UUID().uuidString)")

    private var _wrappedValue: Wrapped
    public var wrappedValue: Wrapped {
        get { queue.sync { _wrappedValue } }
        set { queue.sync { _wrappedValue = newValue } }
    }

    public init(wrappedValue: Wrapped) {
        self._wrappedValue = wrappedValue
    }
}

Sonra sadece şunları yapabilirsiniz:

@NCCSerialized var foo: Int = 10

veya

@NCCSerialized var myData: [SomeStruct] = []

Ardından değişkene normalde yaptığınız gibi erişin.


1
Bu çözümü beğendim, ancak @Decorating millet maliyetini merak ettim, çünkü bunu DispatchQueueyapan kullanıcıdan gizli bir yaratma yan etkisi vardır . Fikrimi rahatlatmak için bu SO referansını buldum: stackoverflow.com/a/35022486/1060314
Adam Venturella

Özellik sarıcı oldukça hafif - sadece bir yapı, yani, yapabileceğiniz en hafif şeylerden biri. DispatchQueue'daki bağlantı için teşekkürler. Diğer çözümler (ve kuyruk yok karşı) queue.sync wrap üzerinde bazı performans testleri yapmak için kafamda vardı, ama bunu yapmamıştı.
drewster

1

Sonuç olarak, Burada dönüş değeri veya geçersizliği içeren daha yaygın bir yol verin ve atın

import Foundation

extension NSObject {


    func synchronized<T>(lockObj: AnyObject!, closure: () throws -> T) rethrows ->  T
    {
        objc_sync_enter(lockObj)
        defer {
            objc_sync_exit(lockObj)
        }

        return try closure()
    }


}

0

Neden kilitleri zorlaştırıyor ve güçlük çekiyorsunuz? Dağıtım Engelleri Kullanın.

Bir dağıtım engeli, eşzamanlı bir kuyruk içinde bir senkronizasyon noktası oluşturur.

Çalışırken, eşzamanlı ve diğer çekirdekler mevcut olsa bile kuyruktaki başka bir bloğun çalışmasına izin verilmez.

Bu özel (yazma) bir kilit gibi geliyorsa, öyle. Bariyer olmayan bloklar paylaşılan (okuma) kilitler olarak düşünülebilir.

Kaynağa tüm erişim kuyruk üzerinden gerçekleştirildiği sürece, engeller çok ucuz senkronizasyon sağlar.


2
Yani, erişimi senkronize etmek için bir GCD kuyruğu kullandığınızı varsayıyorsunuz, ancak orijinal soruda bundan bahsedilmiyor. Ve bir bariyer sadece eşzamanlı bir kuyruk için gereklidir - bir kilidi taklit etmek için karşılıklı hariç tutulan blokları sıralamak için seri bir kuyruk kullanabilirsiniz.
Bill

Sorum, neden bir kilit taklit? Okuduğum kadarıyla, kilitler, sıradaki bir bariyere karşı ek yük nedeniyle cesaretini kırıyor.
Frederick C. Lee

0

ɳuroburɳ temel alınarak bir alt sınıf durumu test edin

class Foo: NSObject {
    func test() {
        print("1")
        objc_sync_enter(self)
        defer {
            objc_sync_exit(self)
            print("3")
        }

        print("2")
    }
}


class Foo2: Foo {
    override func test() {
        super.test()

        print("11")
        objc_sync_enter(self)
        defer {
            print("33")
            objc_sync_exit(self)
        }

        print("22")
    }
}

let test = Foo2()
test.test()

Çıktı:

1
2
3
11
22
33

0

dispatch_barrier_async geçerli iş parçacığını engellememekle birlikte daha iyi bir yoldur.

dispatch_barrier_async (accessQueue, {dictionary [object.ID] = nesne})


-5

Başka bir yöntem, bir üst sınıf oluşturmak ve daha sonra devralmaktır. Bu şekilde GCD'yi daha doğrudan kullanabilirsiniz

class Lockable {
    let lockableQ:dispatch_queue_t

    init() {
        lockableQ = dispatch_queue_create("com.blah.blah.\(self.dynamicType)", DISPATCH_QUEUE_SERIAL)
    }

    func lock(closure: () -> ()) {
        dispatch_sync(lockableQ, closure)
    }
}


class Foo: Lockable {

    func boo() {
        lock {
            ....... do something
        }
    }

10
-1 Kalıtım, artan bağlanma karşılığında size alt tip polimorfizm verir. Eğer eskisine ihtiyacınız yoksa daha sonra kaçının. Tembel olma. Kodun yeniden kullanımı için kompozisyonu tercih edin.
Jano
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.