আমি কীভাবে সমকালীনভাবে পাঠানো ব্লকটি শেষ করতে অপেক্ষা করব?


179

আমি এমন কিছু কোড পরীক্ষা করছি যা গ্র্যান্ড সেন্ট্রাল ডিসপ্যাচ ব্যবহার করে অ্যাসিনক্রোনাস প্রসেসিং করে। টেস্টিং কোডটি এর মতো দেখাচ্ছে:

[object runSomeLongOperationAndDo:^{
    STAssert
}];

পরীক্ষাগুলি অপারেশন শেষ হওয়ার জন্য অপেক্ষা করতে হবে। আমার বর্তমান সমাধানটি এর মতো দেখাচ্ছে:

__block BOOL finished = NO;
[object runSomeLongOperationAndDo:^{
    STAssert
    finished = YES;
}];
while (!finished);

যা কিছুটা অপরিশোধিত দেখাচ্ছে, আপনি কি আরও ভাল কোনও উপায় জানেন? আমি সারিটি উন্মোচন করতে এবং তারপরে কল করে dispatch_sync:

[object runSomeLongOperationAndDo:^{
    STAssert
}];
dispatch_sync(object.queue, ^{});

… তবে এটি সম্ভবত খুব বেশি প্রকাশ করে object

উত্তর:


302

ব্যবহার করার চেষ্টা করছেন dispatch_semaphore। এটি দেখতে কিছু দেখতে হবে:

dispatch_semaphore_t sema = dispatch_semaphore_create(0);

[object runSomeLongOperationAndDo:^{
    STAssert

    dispatch_semaphore_signal(sema);
}];

if (![NSThread isMainThread]) {
    dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
} else {
    while (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW)) { 
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0]]; 
    }
}

এটি ঠিকভাবে আচরণ করা উচিত এমনকি যদি runSomeLongOperationAndDo:সিদ্ধান্ত নেওয়া হয় যে থ্রেডিংয়ের যোগ্যতা অপারেশন আসলে যথেষ্ট দীর্ঘ নয় এবং পরিবর্তে সিঙ্ক্রোনিকভাবে চলছে।


61
এই কোডটি আমার পক্ষে কার্যকর হয়নি। আমার STAssert কখনই কার্যকর করবে না। আমাকে dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; }
নিকটম্রোর

41
এটি সম্ভবত কারণ আপনার সমাপ্তি ব্লকটি মূল সারিতে প্রেরণ করা হয়েছে? ক্যুটি সেমফোরের অপেক্ষায় অবরুদ্ধ এবং তাই ব্লকটি কখনও কার্যকর করে না। ব্লক না করে মূল কাতারে প্রেরণের বিষয়ে এই প্রশ্নটি দেখুন ।
জুল

3
আমি @ জুল এবং নিকটম্রোর পরামর্শ অনুসরণ করেছি। তবে দেখা যাচ্ছে যে এটি অচলাবস্থায় চলেছে। পরীক্ষার কেস '- [ব্লকস্টেস্ট টেস্ট টেস্টঅ্যাসেন্স]' শুরু হয়েছিল। তবে কখনও শেষ হয়নি
এনএসক্রি

3
আপনার কি আরসি এর আওতায় সেমফোর ছেড়ে দেওয়ার দরকার আছে?
পিটার ওয়ারবো

14
এই আমি ঠিক খুঁজছিলাম ছিল। ধন্যবাদ! পছন্দ করুন এআরসি ব্যবহার একটি
প্রেরণ_প্রয়োজনীয়

29

অন্যান্য উত্তরে সম্পূর্ণরূপে আচ্ছাদিত semaphore কৌশল ছাড়াও, এখন আমরা এক্সকোড 6 এ এক্সসিটিস্ট ব্যবহার করতে পারি এর মাধ্যমে অ্যাসিঙ্ক্রোনাস পরীক্ষা করতে XCTestExpectation। এটি অ্যাসিক্রোনাস কোড টেস্ট করার সময় সেমফোরগুলির প্রয়োজনীয়তা হ্রাস করে। উদাহরণ স্বরূপ:

- (void)testDataTask
{
    XCTestExpectation *expectation = [self expectationWithDescription:@"asynchronous request"];

    NSURL *url = [NSURL URLWithString:@"http://www.apple.com"];
    NSURLSessionTask *task = [self.session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        XCTAssertNil(error, @"dataTaskWithURL error %@", error);

        if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
            NSInteger statusCode = [(NSHTTPURLResponse *) response statusCode];
            XCTAssertEqual(statusCode, 200, @"status code was not 200; was %d", statusCode);
        }

        XCTAssert(data, @"data nil");

        // do additional tests on the contents of the `data` object here, if you want

        // when all done, Fulfill the expectation

        [expectation fulfill];
    }];
    [task resume];

    [self waitForExpectationsWithTimeout:10.0 handler:nil];
}

ভবিষ্যতের পাঠকদের পক্ষে, প্রেরণে সেম্যাফোর কৌশলটি যখন একেবারে প্রয়োজন হয়, তখন আমি অবশ্যই স্বীকার করে নিতে পারি যে আমি অনেক নতুন বিকাশকারীকে দেখছি, ভাল অ্যাসিনক্রোনাস প্রোগ্রামিং ধরণের সাথে অপরিচিত, অ্যাসিঙ্ক্রোনাস তৈরির জন্য একটি সাধারণ প্রক্রিয়া হিসাবে সেমফোরসে খুব তাড়াতাড়ি মাধ্যাকর্ষণ করব রুটিনগুলি সুসংগতভাবে আচরণ করে। সবচেয়ে খারাপ যে আমি তাদের অনেকগুলি প্রধান সারি থেকে এই سيمফোর কৌশলটি ব্যবহার করতে দেখেছি (এবং আমাদের কখনই প্রোডাকশন অ্যাপ্লিকেশনগুলিতে মূল সারিটি ব্লক করা উচিত নয়)।

আমি জানি যে এটি এখানে ঘটেনি (যখন এই প্রশ্নটি পোস্ট করা হয়েছিল, তখনকার মতো কোনও দুর্দান্ত সরঞ্জাম ছিল না XCTestExpectation; এছাড়াও, এই পরীক্ষার স্যুটগুলিতে, আমাদের অবশ্যই নিশ্চিত করতে হবে যে অ্যাসিঙ্ক্রোনাস কল না হওয়া পর্যন্ত পরীক্ষা শেষ হয় না)। এটি সেই বিরল পরিস্থিতিতে একটি যেখানে মূল থ্রেড ব্লক করার জন্য সেমফোর কৌশলটি প্রয়োজনীয় হতে পারে।

সুতরাং এই মূল প্রশ্নের লেখকের কাছে আমার ক্ষমাপ্রার্থী, যাদের জন্য সেমফোর কৌশলটি সঠিক, আমি এই সতর্কতাটি সেই সমস্ত নতুন বিকাশকারীকে যারা এই সেমফোর কৌশলটি দেখে এবং তাদের কোডে এটি অ্যাসিঙ্ক্রোনাসের সাথে মোকাবিলার জন্য একটি সাধারণ পদ্ধতির হিসাবে বিবেচনা করে লিখি পদ্ধতি: পূর্বে সতর্ক থাকুন যে দশজনের মধ্যে নয় বার, সেমফোর কৌশলটি নয়অ্যাসিক্রোনাস অপারেশনগুলি গোছানোর সময় সেরা পদ্ধতির। পরিবর্তে, সমাপ্তি ব্লক / ক্লোজার প্যাটার্নগুলির পাশাপাশি ডেলিগেট-প্রোটোকল নিদর্শন এবং বিজ্ঞপ্তিগুলির সাথে নিজেকে পরিচিত করুন। এগুলি প্রায়শই সিঙ্ক্রোনাসের সাথে আচরণ করার জন্য সেমফোরাস ব্যবহার না করে অ্যাসিক্রোনাস কার্যগুলি পরিচালনা করার অনেক বেশি ভাল উপায়। সাধারণত অ্যাসিঙ্ক্রোনাস কাজগুলি অ্যাসিঙ্ক্রোনাস আচরণের জন্য তৈরি করা হয়েছিল এমন ভাল কারণ রয়েছে, সুতরাং সেগুলি সিঙ্ক্রোনালি আচরণ করার চেষ্টা করার চেয়ে সঠিক অ্যাসিনক্রোনাস প্যাটার্নটি ব্যবহার করুন।


1
আমি মনে করি এটি এখনই গ্রহণযোগ্য উত্তর হওয়া উচিত। এখানে ডক্সগুলিও রয়েছে: বিকাশকারী
অ্যাপ্লিকেশন

আমি এই সম্পর্কে একটি প্রশ্ন আছে। আমি কিছু অ্যাসিক্রোনাস কোড পেয়েছি যা একটি ডকুমেন্ট ডাউনলোড করতে প্রায় এক ডজন এএফ নেট নেটওয়ার্কিং ডাউনলোড কল করে। আমি একটি এ ডাউনলোড শিডিউল করতে চাই NSOperationQueue। আমি যদি সেমফোরের মতো কিছু ব্যবহার না করি তবে ডকুমেন্ট ডাউনলোডের NSOperationসমস্ত তত্ক্ষণাত্ সম্পূর্ণ হয়ে যাবে এবং ডাউনলোডগুলির সত্যিকারের সারি নেই won't এগুলি একযোগে আরও এগিয়ে যাবে, যা আমি চাই না। Semaphores এখানে যুক্তিসঙ্গত? বা অন্যদের অ্যাসিনক্রোনাস সমাপ্তির জন্য এনএসপ্পেরেশনগুলি অপেক্ষা করার আরও ভাল উপায় আছে কি? অথবা অন্য কিছু?
বেনজোহান

না, এই পরিস্থিতিতে semaphores ব্যবহার করবেন না। যদি আপনার অপারেশন সারি থাকে যা আপনি AFHTTPRequestOperationঅবজেক্টগুলিকে যুক্ত করছেন , তবে আপনাকে কেবল একটি সমাপ্তির ক্রিয়া তৈরি করতে হবে (যা আপনি অন্যান্য ক্রিয়াকলাপগুলির উপর নির্ভরশীল করে তুলবেন)। অথবা প্রেরণ গোষ্ঠী ব্যবহার করুন। বিটিডাব্লু, আপনি বলছেন যে আপনি তাদের একসাথে চলতে চান না, যা আপনার যদি প্রয়োজন হয় তবে তা ঠিক, তবে আপনি একযোগে না হয়ে ক্রমান্বয়ে এই কাজটি করার জন্য গুরুতর পারফরম্যান্স জরিমানা প্রদান করেন। আমি সাধারণত maxConcurrentOperationCount4 বা 5 এর ব্যবহার করি
রব

27

আমি সম্প্রতি এই সমস্যাটিতে আবার এসেছি এবং নিম্নলিখিত বিভাগটি লিখেছি NSObject:

@implementation NSObject (Testing)

- (void) performSelector: (SEL) selector
    withBlockingCallback: (dispatch_block_t) block
{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    [self performSelector:selector withObject:^{
        if (block) block();
        dispatch_semaphore_signal(semaphore);
    }];
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    dispatch_release(semaphore);
}

@end

এইভাবে আমি সহজেই কলব্যাকের সাথে অ্যাসিঙ্ক্রোনাস কলকে পরীক্ষার ক্ষেত্রে একটি সিঙ্ক্রোনাস রূপে পরিণত করতে পারি:

[testedObject performSelector:@selector(longAsyncOpWithCallback:)
    withBlockingCallback:^{
    STAssert
}];

24

সাধারণত এই উত্তরগুলির কোনও ব্যবহার করবেন না, তারা প্রায়শই স্কেল করে না (এখানে এবং সেখানে ব্যতিক্রম রয়েছে, নিশ্চিত)

এই পদ্ধতির সাথে জিসিডি কীভাবে কাজ করা যায় তার সাথে বেমানান এবং এটি ডেডলক সৃষ্টি করে এবং / অথবা ননস্টপ পোলিংয়ের মাধ্যমে ব্যাটারি মেরে ফেলবে।

অন্য কথায়, আপনার কোডটি পুনর্বিন্যাস করুন যাতে কোনও ফলাফলের জন্য কোনও সুসংগত অপেক্ষা না করা হয়, তবে পরিবর্তে রাষ্ট্রের পরিবর্তনের বিষয়ে অবহিত হওয়ার ফলাফলকে মোকাবেলা করুন (যেমন কলব্যাকস / ডেলিগেট প্রোটোকল, উপলব্ধ হওয়া, দূরে যাওয়া, ত্রুটি ইত্যাদি)। (আপনি যদি কলব্যাক হেল্প পছন্দ না করেন তবে এগুলিকে ব্লকগুলিতে রিফ্যাক্টর করা যেতে পারে Because) কারণ অ্যাপ্লিকেশনটিতে এটি কোনও মিথ্যা ফ্যাডের আড়ালে লুকিয়ে রাখার চেয়ে কীভাবে প্রকৃত আচরণটি প্রকাশ করা যায়।

পরিবর্তে, এনএসএনটিফিকেশন সেন্টার ব্যবহার করুন , আপনার ক্লাসের কলব্যাক সহ একটি কাস্টম প্রতিনিধি প্রোটোকল সংজ্ঞায়িত করুন। এবং যদি আপনি ডেলিগেট কলব্যাকগুলি পুরোপুরি উপহাস করতে পছন্দ করেন না, তবে তাদের একটি কংক্রিট প্রক্সি ক্লাসে আবদ্ধ করুন যা কাস্টম প্রোটোকল প্রয়োগ করে এবং বৈশিষ্ট্যগুলিতে বিভিন্ন ব্লক সংরক্ষণ করে। সম্ভবত সুবিধার্থে নির্মাণকারীও সরবরাহ করুন।

প্রাথমিক কাজটি খানিকটা বেশি তবে এটি দীর্ঘমেয়াদে ভয়াবহ রেস-কন্ডিশন এবং ব্যাটারি-হত্যার পোলিংয়ের সংখ্যা হ্রাস করবে।

(উদাহরণের জন্য জিজ্ঞাসা করবেন না, কারণ এটি তুচ্ছ এবং আমাদের উদ্দেশ্য-সি বেসিকগুলি শিখতেও সময় ব্যয় করতে হয়েছিল।)


1
এটিও
আবজ

8

এখানে একটি নিফটি ট্রিক যা সেমফোর ব্যবহার করে না:

dispatch_queue_t serialQ = dispatch_queue_create("serialQ", DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQ, ^
{
    [object doSomething];
});
dispatch_sync(serialQ, ^{ });

আপনি যা করছেন তা dispatch_syncখালি ব্লকটি ব্যবহার করে অপেক্ষা করুন সিঙ্ক্রোনালি সিরিয়াল প্রেরণের সারিটিতে অপেক্ষা করুন যতক্ষণ না এ-সিঙ্ক্রোনাস ব্লকটি শেষ হয়।


এই উত্তরের সমস্যাটি হ'ল এটি অপের মূল সমস্যাটির সমাধান করে না, এটি হ'ল যে এপিআই ব্যবহার করা দরকার এটি একটি যুক্তি হিসাবে সম্পূর্ণ হয় এবং তত্ক্ষণাত্ ফিরে আসে। এই উত্তরটির অ্যাসিঙ্ক ব্লকের ভিতরে API তারপরে সিঙ্ক ব্লকটি সম্পূর্ণ হওয়ার আগে হ্যান্ডলারটি কার্যকর করা হবে।
বিটিআরইউ

6
- (void)performAndWait:(void (^)(dispatch_semaphore_t semaphore))perform;
{
  NSParameterAssert(perform);
  dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
  perform(semaphore);
  dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
  dispatch_release(semaphore);
}

ব্যবহারের উদাহরণ:

[self performAndWait:^(dispatch_semaphore_t semaphore) {
  [self someLongOperationWithSuccess:^{
    dispatch_semaphore_signal(semaphore);
  }];
}];

2

এর রয়েছে SenTestingKitAsync আপনার কাছে লিখনের কোড দেয় ভালো:

- (void)testAdditionAsync {
    [Calculator add:2 to:2 block^(int result) {
        STAssertEquals(result, 4, nil);
        STSuccess();
    }];
    STFailAfter(2.0, @"Timeout");
}

( বিশদের জন্য অবজেক্ট.ও নিবন্ধটি দেখুন )) এবং এক্সকোড 6 সাল থেকে একটি AsynchronousTestingবিভাগ রয়েছে XCTestযা আপনাকে এই জাতীয় কোড লিখতে দেয়:

XCTestExpectation *somethingHappened = [self expectationWithDescription:@"something happened"];
[testedObject doSomethigAsyncWithCompletion:^(BOOL succeeded, NSError *error) {
    [somethingHappened fulfill];
}];
[self waitForExpectationsWithTimeout:1 handler:NULL];

1

আমার পরীক্ষার একটি থেকে এখানে বিকল্প রয়েছে:

__block BOOL success;
NSCondition *completed = NSCondition.new;
[completed lock];

STAssertNoThrow([self.client asyncSomethingWithCompletionHandler:^(id value) {
    success = value != nil;
    [completed lock];
    [completed signal];
    [completed unlock];
}], nil);    
[completed waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
[completed unlock];
STAssertTrue(success, nil);

1
উপরের কোডটিতে একটি ত্রুটি রয়েছে। "এই পদ্ধতিটি কল করার আগে আপনাকে অবশ্যই রিসিভারটি লক করতে হবে" এর জন্য NSCondition ডকুমেন্টেশন থেকে -waitUntilDate:। সুতরাং -unlockপরে হওয়া উচিত -waitUntilDate:
প্যাট্রিক

এটি একাধিক থ্রেড বা রান সারি ব্যবহার করে এমন কোনও স্কেল করে না।

0
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[object blockToExecute:^{
    // ... your code to execute
    dispatch_semaphore_signal(sema);
}];

while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) {
    [[NSRunLoop currentRunLoop]
        runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0]];
}

এটা আমার জন্য এটি।


3
ভাল, এটি উচ্চ সিপু ব্যবহারের কারণ ঘটায়
কেভিন

4
@ কেভিন ইয়ুপ, এটি ঘেটো পোলিং যা ব্যাটারিটি মেরে ফেলবে।

@ ব্যারি, কীভাবে এটি বেশি ব্যাটারি গ্রাস করে। দয়া করে গাইড করুন।
pkc456

@ pkc456 কীভাবে পোলিং এবং অ্যাসিক্রোনাস নোটিফিকেশন কাজ করে তার মধ্যে পার্থক্য সম্পর্কে একটি কম্পিউটার বিজ্ঞানের বইটিতে দেখুন। শুভকামনা।

2
সাড়ে চার বছর পরে এবং আমি যে জ্ঞান এবং অভিজ্ঞতা অর্জন করেছি তা দিয়ে আমি আমার উত্তরটি সুপারিশ করব না।

0

কখনও কখনও, টাইমআউট লুপগুলিও সহায়ক। আপনি async কলব্যাক পদ্ধতি থেকে কিছু (BOOL হতে পারে) সিগন্যাল না পাওয়া পর্যন্ত অপেক্ষা করতে পারেন, তবে যদি কখনও প্রতিক্রিয়া না ঘটে এবং আপনি সেই লুপটি ভেঙে ফেলতে চান? নীচে এখানে সমাধান দেওয়া হয়েছে, বেশিরভাগের উপরে উত্তর দেওয়া হয়েছে তবে সময়সীমা সংযোজন সহ।

#define CONNECTION_TIMEOUT_SECONDS      10.0
#define CONNECTION_CHECK_INTERVAL       1

NSTimer * timer;
BOOL timeout;

CCSensorRead * sensorRead ;

- (void)testSensorReadConnection
{
    [self startTimeoutTimer];

    dispatch_semaphore_t sema = dispatch_semaphore_create(0);

    while (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW)) {

        /* Either you get some signal from async callback or timeout, whichever occurs first will break the loop */
        if (sensorRead.isConnected || timeout)
            dispatch_semaphore_signal(sema);

        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                                 beforeDate:[NSDate dateWithTimeIntervalSinceNow:CONNECTION_CHECK_INTERVAL]];

    };

    [self stopTimeoutTimer];

    if (timeout)
        NSLog(@"No Sensor device found in %f seconds", CONNECTION_TIMEOUT_SECONDS);

}

-(void) startTimeoutTimer {

    timeout = NO;

    [timer invalidate];
    timer = [NSTimer timerWithTimeInterval:CONNECTION_TIMEOUT_SECONDS target:self selector:@selector(connectionTimeout) userInfo:nil repeats:NO];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

-(void) stopTimeoutTimer {
    [timer invalidate];
    timer = nil;
}

-(void) connectionTimeout {
    timeout = YES;

    [self stopTimeoutTimer];
}

1
একই সমস্যা: ব্যাটারির আয়ু ব্যর্থ।

1
@ ব্যারি আপনি কোডটি দেখেছেন কিনা তা নিশ্চিত নন। TIMEOUT_SECONDS পিরিয়ড রয়েছে যার মধ্যে যদি অ্যাসিঙ্ক কল সাড়া না দেয় তবে লুপটি ভেঙে যাবে। অচলাবস্থা ভাঙার জন্য এটি হ্যাক the এই কোডটি ব্যাটারিটি না মেরে নিখুঁতভাবে কাজ করে।
খুলজা সিম সিম

0

সমস্যার খুব প্রাথমিক সমাধান:

void (^nextOperationAfterLongOperationBlock)(void) = ^{

};

[object runSomeLongOperationAndDo:^{
    STAssert
    nextOperationAfterLongOperationBlock();
}];

0

সুইফট 4:

রিমোট অবজেক্ট তৈরি করার synchronousRemoteObjectProxyWithErrorHandlerপরিবর্তে ব্যবহার করুন remoteObjectProxy। একটি semaphore জন্য আর প্রয়োজন নেই।

উদাহরণস্বরূপ নীচে প্রক্সি থেকে প্রাপ্ত সংস্করণটি ফিরে আসবে। synchronousRemoteObjectProxyWithErrorHandlerএটি ছাড়াই ক্রাশ হবে (অ্যাক্সেস অযোগ্য মেমরির অ্যাক্সেসের চেষ্টা করা):

func getVersion(xpc: NSXPCConnection) -> String
{
    var version = ""
    if let helper = xpc.synchronousRemoteObjectProxyWithErrorHandler({ error in NSLog(error.localizedDescription) }) as? HelperProtocol
    {
        helper.getVersion(reply: {
            installedVersion in
            print("Helper: Installed Version => \(installedVersion)")
            version = installedVersion
        })
    }
    return version
}

-1

আমার পদ্ধতিটি চালানোর আগে কোনও ইউআইবিউব ভিউ লোড না হওয়া পর্যন্ত আমাকে অপেক্ষা করতে হবে, আমি এই থ্রেডে উল্লিখিত সেমফোর পদ্ধতির সংমিশ্রণে জিসিডি ব্যবহার করে মূল থ্রেডে ইউআইউইউবভিউ প্রস্তুত চেকগুলি সম্পাদন করে এই কাজটি করতে সক্ষম হয়েছি। চূড়ান্ত কোডটি এর মতো দেখাচ্ছে:

-(void)myMethod {

    if (![self isWebViewLoaded]) {

            dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

            __block BOOL isWebViewLoaded = NO;

            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

                while (!isWebViewLoaded) {

                    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)((0.0) * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                        isWebViewLoaded = [self isWebViewLoaded];
                    });

                    [NSThread sleepForTimeInterval:0.1];//check again if it's loaded every 0.1s

                }

                dispatch_sync(dispatch_get_main_queue(), ^{
                    dispatch_semaphore_signal(semaphore);
                });

            });

            while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) {
                [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0]];
            }

        }

    }

    //Run rest of method here after web view is loaded

}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.