Как вернуть внешнюю функцию из внутренней асинхронной функции в Objective-C

Я хочу вернуться из внешней функции из внутренней асинхронной функции. В Swift я бы использовал для этой цели обработчик завершения, который вышел бы из функции. Но в Objective-C обработчик завершения фактически не возвращается из функции:

Моя функция выглядит так:

-(void)chosenFrom:(NSDictionary<NSString *,id> *)info{

    [self asyncCode:info withCompletion:^(NSData *imageData) {
        if(imageData) {
             // I want to return from  chosenFrom function ***inside here.***
        }
    }];

// This is to illustrate  completion handler don't escape
[self checkCompletionEscaping:^(NSString * lad) {
    NSLog(@"Check me %@", lad);// It would print all 3 lines below.
}];
}

-(void) checkCompletionEscaping:(void(^)(NSString * lad)) completion {
completion(@"Hello"); // completion handler should've escaped from func.
completion(@"Shivam");
completion(@"How are you");
}

Если бы я использовал Swift, я мог бы легко вернуться из внешней функции из внутренней внутренней функции, используя обработчик завершения:

private func getHistoryKeys(searchterm: String, completion: @escaping () -> ()) {
  let url = PubmedAPI.createEsearchURL(searchString: searchterm)
  let task = session.dataTask(with: url) { (data, response, error) in
   if let error = error {
      completion() // This would work as return
   } else {
      completion() // Same as return
   }
  }
 task.resume()
}

PS: экранирование означает возврат из функции точно так же, как оператор return.


person shivam pokhriyal    schedule 30.09.2018    source источник
comment
Непонятно, что вы пытаетесь здесь сделать, в частности, что вы используете для обозначения термина экранирование. Вы подразумеваете, что знаете, как делать то, что хотите, в Swift, было бы полезно, если бы вы отредактировали свой вопрос (не делайте этого в комментариях) и включили свою версию Swift checkCompletionEscaping и описали, как ее поведение отличается от версии Objectove-C . Это поможет людям помочь вам.   -  person CRD    schedule 30.09.2018
comment
@CRD Обновленный вопрос   -  person shivam pokhriyal    schedule 30.09.2018
comment
Вы не воспроизвели тот же пример, что и в Objective-C, и @escaping в вашем коде Swift, к сожалению, не означает возврат из функции, как оператор return, а что-то совершенно другое. Кажется, вы ищете что-то вроде нелокального перехода в асинхронном контексте, но я говорю кажется, поскольку вы, кажется, говорите, что можете делать все, что хотите, в Swift. и в нем отсутствует такая конструкция. Так что либо я упускаю очевидное, либо вам нужно яснее. Найдите в SO вопросы об ожидании результатов асинхронных функций, это распространенный вопрос, и вы можете найти то, что вам нужно.   -  person CRD    schedule 30.09.2018
comment
По сути, это дубликат вашего предыдущего вопроса. всего несколькими часами раньше. Пожалуйста, удалите один из этих двух вопросов и отредактируйте другой по мере необходимости.   -  person rmaddy    schedule 30.09.2018


Ответы (2)


Проще просто вызвать другую функцию, которая сообщает, что она завершена.

-(void)chosenFrom:(NSDictionary<NSString *,id> *)info{

    [self asyncCode:info withCompletion:^(NSData *imageData) {
        if(imageData) {
             [self completedAsync:imageData];
        }
    }];

}

-(void)completedAsync:(NSData*) imageData {
  // do your thang.
}
person GeneCode    schedule 30.09.2018

Кажется, вы дважды задали один и тот же вопрос разными способами, и люди застряли, помогая вам. Это не ответ как таковой, так как я действительно не знаю вопроса, но, надеюсь, это может помочь вам найти ответ или задать вопрос по-другому, чтобы люди могли вам помочь.

Начнем с вашего утверждения:

экранирование означает возврат из функции точно так же, как оператор return

и вы упомянули об использовании @escaping в Swift. Хотя термин экранирование может использоваться в некоторых языках для обозначения того, что вы говорите, это совсем не то, что он означает в Swift.

Разумно запутаться в том, что это означает в Swift, поскольку это, по сути, делает то, что может / должно быть скрытой оптимизацией компилятора, видимой для программиста на языке. Определение в Swift:

Говорят, что замыкание экранирует функцию, когда замыкание передается функции в качестве аргумента, но вызывается после возврата из функции. Когда вы объявляете функцию, которая принимает замыкание в качестве одного из своих параметров, вы можете написать @escaping перед типом параметра, чтобы указать, что закрытию разрешено выйти.

Один из способов избежать замыкания — сохранить его в переменной, которая определена вне функции. Например, многие функции, запускающие асинхронную операцию, принимают аргумент закрытия в качестве обработчика завершения. Функция возвращает значение после запуска операции, но замыкание не вызывается до тех пор, пока операция не завершится — замыкание должно выйти, чтобы его можно было вызвать позже.

Язык программирования Swift (Swift 4.2)

Это говорит вам о том, что @escaping влияет на то, как замыкание может храниться и использоваться, а не на то, что на самом деле делает само замыкание при вызове. При вызове замыкание выполняет одни и те же операции независимо от того, помечено ли оно как @escaping или нет.

Двигаясь дальше, пример, используемый для иллюстрации @escaping, имеет отношение к тому, что кажется вашей ситуацией - вы, очевидно, хотите иметь метод, скажем, A, инициирующий асинхронную операцию, скажем, *B**, передавая ее замыкание, скажем, C, которое при последующем вызове приведет к возврату A. Это невозможно, так как при вторжении C нет вызова A для возврата. Посмотрите на пример еще раз, добавленный акцент:

Один из способов избежать замыкания — сохранить его в переменной, которая определена вне функции. Например, многие функции, запускающие асинхронную операцию, принимают аргумент закрытия в качестве обработчика завершения. Функция возвращает значение после запуска операции, но закрытие не вызывается до тех пор, пока операция не будет завершена

После того, как A запустил B, он возвратит, к моменту вызова C вызов A< /em>, который запустил B, уже вернулся. Вы, видимо, просите невозможного!

Так что же вы пытаетесь сделать?

Возможно, вы хотите, чтобы A и запускаемая им асинхронная операция B отображались как один синхронный блок, а для A не возвращаться, пока B не выполнит свою работу.

Бывают редкие случаи, когда требуется оборачивать асинхронность синхронными операциями, и гораздо больше случаев, когда люди пытаются сделать это, чтобы упростить обработку асинхронности, но в конечном итоге уничтожают все преимущества асинхронности в процессе. Сделать такое обертывание часто кажется обманчиво простым; но если вы хорошо разбираетесь в блочной модели GCD, семафорах, потоках, блокировке и тупик содержит ловушки для неосторожных.

Если вы слишком намерены попытаться обернуть асинхронность, лучше использовать ее вместо этого, в вашем случае выясните, как заставить ваше закрытие C делать то, что необходимо, когда оно вызывается асинхронно дольше после соответствующего вызов вашего метода A завершен и больше не существует. Тридцать лет назад асинхронность была эзотерическим завершением повседневного программирования, сегодня она лежит в ее основе, ее нужно понимать и использовать.

Если после попытки использовать асинхронность вы решите, что у вас есть один из тех редких случаев, когда его нужно скрыть внутри синхронной оболочки, выполните поиск в SO для асинхронного, семафора и т. д. и вы должны найти решение.

Если вы застряли с асинхронностью или на самом деле спрашиваете о чем-то совершенно другом, задайте новый вопрос, покажите, что вы сделали/пытались/и т. д., и кто-то, несомненно, поможет вам сделать следующий шаг. .

ХТН

person CRD    schedule 01.10.2018
comment
Это не ответ как таковой, но опубликованный как ответ. :D - person GeneCode; 10.10.2018
comment
@GeneCode - Это немного превысило лимит комментариев ;-) - person CRD; 10.10.2018