dispatch_once
ভাষার সংস্করণ 3-এ পরিবর্তনের পরে সুইফটে নতুন সিনট্যাক্সটি কী ? পুরাতন সংস্করণটি নিম্নরূপ ছিল।
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
}
}
এইগুলি libdispatch এ পরিবর্তন হয়েছিল।
dispatch_once
ভাষার সংস্করণ 3-এ পরিবর্তনের পরে সুইফটে নতুন সিনট্যাক্সটি কী ? পুরাতন সংস্করণটি নিম্নরূপ ছিল।
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
}
}
এইগুলি libdispatch এ পরিবর্তন হয়েছিল।
pod 'SwiftDispatchOnce', '~> 1.0'
চিয়ার্স। :]
উত্তর:
ডক থেকে :
প্রেরণ
বিনামূল্যে ফাংশন dispatch_once সুইফট আর উপলব্ধ নেই। সুইফ্টে, আপনি অলসভাবে প্রাথমিক গ্লোবাল বা স্থিতিশীল বৈশিষ্ট্যগুলি ব্যবহার করতে পারেন এবং একই থ্রেড-সুরক্ষা পেতে পারেন এবং প্রেরণ_অনস সরবরাহ করা হিসাবে একবার বলা গ্যারান্টি পেতে পারেন। উদাহরণ:
let myGlobal: () = { … global contains initialization in a call to a closure … }()
_ = myGlobal // using myGlobal will invoke the initialization code only the first time it is used.
dispatch_once
পরিষ্কার ছিল। এটি, দুর্ভাগ্যক্রমে, কুশ্রী এবং বিভ্রান্তিকর ..
অলস প্রারম্ভিক গ্লোবালগুলি ব্যবহার করে কিছু এক সময় সূচনা করার জন্য এটি বোঝা যায়, অন্য ধরণের ক্ষেত্রে এটি বোধগম্য নয়। এটি সিলেটনের মতো জিনিসের জন্য অলস সূচনাযুক্ত গ্লোবালগুলি ব্যবহার করতে প্রচুর অর্থবোধ করে, এটি একটি সুইজল সেটআপ রক্ষার মতো বিষয়গুলির জন্য খুব বেশি অর্থবোধ করে না।
এখানে প্রেরণ_অনসের একটি সুইফট 3 শৈলীর প্রয়োগ রয়েছে:
public extension DispatchQueue {
private static var _onceTracker = [String]()
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token: String, block:@noescape(Void)->Void) {
objc_sync_enter(self); defer { objc_sync_exit(self) }
if _onceTracker.contains(token) {
return
}
_onceTracker.append(token)
block()
}
}
এখানে একটি উদাহরণ ব্যবহার:
DispatchQueue.once(token: "com.vectorform.test") {
print( "Do This Once!" )
}
বা একটি ইউইউডি ব্যবহার করে
private let _onceToken = NSUUID().uuidString
DispatchQueue.once(token: _onceToken) {
print( "Do This Once!" )
}
যেহেতু আমরা বর্তমানে সুইফট 2 থেকে 3 এ স্থানান্তরের সময়ে রয়েছি, এখানে সুইফট 2 বাস্তবায়ন উদাহরণ:
public class Dispatch
{
private static var _onceTokenTracker = [String]()
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token token: String, @noescape block:dispatch_block_t) {
objc_sync_enter(self); defer { objc_sync_exit(self) }
if _onceTokenTracker.contains(token) {
return
}
_onceTokenTracker.append(token)
block()
}
}
objc_sync_enter
এবং objc_sync_exit
আর।
টড কানিংহামের উপরের উত্তরটি প্রসারিত করে, আমি একটি অন্য পদ্ধতি যুক্ত করেছি যা ফাইল, ফাংশন এবং লাইন থেকে স্বয়ংক্রিয়ভাবে টোকেন তৈরি করে।
public extension DispatchQueue {
private static var _onceTracker = [String]()
public class func once(file: String = #file,
function: String = #function,
line: Int = #line,
block: () -> Void) {
let token = "\(file):\(function):\(line)"
once(token: token, block: block)
}
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token: String,
block: () -> Void) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
guard !_onceTracker.contains(token) else { return }
_onceTracker.append(token)
block()
}
}
সুতরাং কল করা সহজ হতে পারে:
DispatchQueue.once {
setupUI()
}
এবং আপনি যদি চান তবে একটি টোকেন নির্দিষ্ট করতে পারেন:
DispatchQueue.once(token: "com.hostname.project") {
setupUI()
}
আমি মনে করি আপনি দুটি মডিউলে একই ফাইল থাকলে আপনি একটি সংঘর্ষ পেতে পারেন। খুব খারাপ নেই#module
সম্পাদনা করুন
সহজ সমাধান
lazy var dispatchOnce : Void = { // or anyName I choose
self.title = "Hello Lazy Guy"
return
}()
ব্যবহার মত
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
_ = dispatchOnce
}
আপনি যদি এখনও একটি ব্রিজিং শিরোলেখ যোগ করেন তবে আপনি এটি ব্যবহার করতে পারেন:
typedef dispatch_once_t mxcl_dispatch_once_t;
void mxcl_dispatch_once(mxcl_dispatch_once_t *predicate, dispatch_block_t block);
তারপরে .m
কোথাও:
void mxcl_dispatch_once(mxcl_dispatch_once_t *predicate, dispatch_block_t block) {
dispatch_once(predicate, block);
}
আপনি এখন mxcl_dispatch_once
সুইফ্ট থেকে ব্যবহার করতে সক্ষম হওয়া উচিত ।
এর পরিবর্তে অ্যাপলের পরামর্শ অনুযায়ী আপনার ব্যবহার করা উচিত, তবে আমার কয়েকটি বৈধ ব্যবহার ছিল যেখানে আমার dispatch_once
দুটি ফাংশনে একক টোকেনের প্রয়োজন ছিল এবং অ্যাপল তার পরিবর্তে যা সরবরাহ করে তা কভার করা যায় না।
আপনি এই জাতীয় একটি শীর্ষ স্তরের ভেরিয়েবল ফাংশন ঘোষণা করতে পারেন:
private var doOnce: ()->() = {
/* do some work only once per instance */
return {}
}()
তারপরে এটিকে যে কোনও জায়গায় কল করুন:
doOnce()
সুইফট 3: যারা পুনরায় ব্যবহারযোগ্য ক্লাসগুলি (বা কাঠামো) পছন্দ করেন তাদের জন্য:
public final class /* struct */ DispatchOnce {
private var lock: OSSpinLock = OS_SPINLOCK_INIT
private var isInitialized = false
public /* mutating */ func perform(block: (Void) -> Void) {
OSSpinLockLock(&lock)
if !isInitialized {
block()
isInitialized = true
}
OSSpinLockUnlock(&lock)
}
}
ব্যবহার:
class MyViewController: UIViewController {
private let /* var */ setUpOnce = DispatchOnce()
override func viewWillAppear() {
super.viewWillAppear()
setUpOnce.perform {
// Do some work here
// ...
}
}
}
আপডেট (28 এপ্রিল 2017): ম্যাকোস এসডিকে 10.12-এ যথাযোগ্য হ্রাস সতর্কতার OSSpinLock
সাথে প্রতিস্থাপন করা os_unfair_lock
হয়েছে।
public final class /* struct */ DispatchOnce {
private var lock = os_unfair_lock()
private var isInitialized = false
public /* mutating */ func perform(block: (Void) -> Void) {
os_unfair_lock_lock(&lock)
if !isInitialized {
block()
isInitialized = true
}
os_unfair_lock_unlock(&lock)
}
}
OSSpinLock
সঙ্গে প্রতিস্থাপন os_unfair_lock
। বিটিডব্লিউ: এখানে একটি ভাল ডাব্লুডাব্লুডিসি ভিডিও রয়েছে Concurrent Programming
: বিকাশকারী.এপলস
আমি উপরের উত্তরগুলি উন্নতি করে ফলাফল পেয়েছি:
import Foundation
extension DispatchQueue {
private static var _onceTracker = [AnyHashable]()
///only excute once in same file&&func&&line
public class func onceInLocation(file: String = #file,
function: String = #function,
line: Int = #line,
block: () -> Void) {
let token = "\(file):\(function):\(line)"
once(token: token, block: block)
}
///only excute once in same Variable
public class func onceInVariable(variable:NSObject, block: () -> Void){
once(token: variable.rawPointer, block: block)
}
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token: AnyHashable,block: () -> Void) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
guard !_onceTracker.contains(token) else { return }
_onceTracker.append(token)
block()
}
}
extension NSObject {
public var rawPointer:UnsafeMutableRawPointer? {
get {
Unmanaged.passUnretained(self).toOpaque()
}
}
}
আপনি যদি পূর্ববর্তী সংস্করণগুলি সমর্থন করার প্রয়োজন হয় তবে আপনি যদি সুইফট ১.২ বা তার বেশি বা তার উপরে নেস্টেড স্ট্রাক পদ্ধতির ব্যবহার করছেন তবে ক্লাস ধ্রুবক পদ্ধতির ব্যবহার করুন। সুইফটে সিঙ্গলটন প্যাটার্নের অন্বেষণ। নীচের সমস্ত পন্থা অলস সূচনা এবং থ্রেড সুরক্ষা সমর্থন করে। dispatch_once পদ্ধতির সুইফট ৩.০ এ কাজ করা হয় না
পদ্ধতির এ: ক্লাস ধ্রুবক
class SingletonA {
static let sharedInstance = SingletonA()
init() {
println("AAA");
}
}
পদ্ধতির বি: নেস্টেড স্ট্রাক্ট
class SingletonB {
class var sharedInstance: SingletonB {
struct Static {
static let instance: SingletonB = SingletonB()
}
return Static.instance
}
}
পদ্ধতির সি: প্রেরণ_অনসেস
class SingletonC {
class var sharedInstance: SingletonC {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: SingletonC? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = SingletonC()
}
return Static.instance!
}
}