Цель C Как вернуть внешнюю функцию изнутри асинхронной внутренней функции - PullRequest
0 голосов
/ 30 сентября 2018

Я хочу вернуться из внешней функции изнутри асинхронной внутренней функции.В быстром я бы использовал обработчик завершения для этой цели, который будет выходить из функции.Но в задаче 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: экранирование означает возврат из функции, так же как и инструкцию возврата.

Ответы [ 2 ]

0 голосов
/ 01 октября 2018

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

Давайте начнем с вашегооператор:

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

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

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

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

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

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

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

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

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

После того, как A началось B it возвращает , к тому времени, когда C вызывается, вызов A , который начался B , уже возвращен .Вы, очевидно, просите невозможного!

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

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

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

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

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

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

HTH

0 голосов
/ 01 октября 2018

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

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

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

}

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