2016-05-24 1 views
1

У нас есть singleton WebService, который обрабатывает все наши вызовы API. Все работает отлично, если у нас не сразу есть несколько вызовов API из разных ViewControllers.Как обработчик завершения может вернуться к неправильному ViewController?

  1. ППГ посылает запрос
  2. VCB посылает Заявка В
  3. ответ Б возвращается VCB
  4. Ответа возвращается в СВУ - это вызывает исключение

WebService:

typealias ServiceResponse = (NSDictionary!, NSError!) ->() 

class WebService: NSObject { 

var serviceResponse : ServiceResponse! 

class var sharedInstance:WebService { 
    struct Singleton { 
     static let instance = WebService() 
    } 
    return Singleton.instance 
} 

func callWebserviceWith(paramsDict: NSDictionary, sendAccessToken: Bool, onCompletion: ServiceResponse) -> Void { 
    serviceResponse = onCompletion 

Как это может случиться?

+3

* "это вызывает исключение" * - какого рода? Наличие * любого * состояния, запоминаемого в любом синглтоне, является очень-очень-очень-очень плохой идеей. Мне не нужно объяснять это больше, потому что вы создали здесь главный пример! 'serviceResponse = onCompletion', безусловно, вызовет у вас массу проблем. Что вы ожидаете, когда звонки в «callWebserviceWith» происходят близко друг к другу? – luk2302

+0

Почему бы не использовать другой экземпляр для каждого ViewController? – 4oby

+0

@ luk2302 Uhu yep, мы унаследовали этот код, и я пытаюсь понять, почему этот шаблон дизайна был выбран и каким может быть лучший подход к переходу. Исключение просто вызвано тем, что данные ответа не являются правильной структурой. – Leon

ответ

1

Проблема не с блоком завершения, то, как вы имеете дело с ним :)

Ошибки

Вашего синглтоном класс ServiceResponse имеет имя serviceResponse переменного класса, что означает, что будет только одна переменными названный serviceResponse в памяти (Эта переменная указатель, содержащее ссылку на указатель на функцию)

var serviceResponse : ServiceResponse! 

Теперь, когда VCA делает вызов он передает свою точку er для блока кода позволяет вызывать VCAF1, теперь ваш serviceResponse будет иметь значение VCAF1, предположим, что ваш веб-сервис еще не завершен, и VCB вызывает веб-сервис и передает его указатель VCBf1, который абсолютно отличается от VCAF1 (разные функции или блоки кода все вместе), но ваш serviceResponse не беспокоит, это просто забывает о его раннем значении и начинает удерживать VCBf1.

Теперь ваш первый ответ на вызов службы приходит, и ваш код говорит, что выполняет код, для которого я держу ссылку в serviceResponse. Та да !!!!!ошибка :) Вы выполняете неверный код :)

Решение

я не нашел каких-либо проблем в области дизайна, чтобы быть честным, но тогда я мог бы быть неправильно :) Создание одноэлементный класс для веб-сервиса очень распространенным подходом , затворы являются не differrent то блоков в ObjectiveC, и я никогда не имел проблем с одноплодной шаблон дизайна путем из моей карьеры как IOS разработчик :)

Все, что вам нужно сделать

  1. удаление переменной serviceResponse

  2. изменить функцию использовать функцию arguement вместо экземпляра свойства

func callWebserviceWith(paramsDict: NSDictionary, sendAccessToken: Bool, onCompletion: ServiceResponse) -> Void { 
    //when done use funtion arguement passed :) 
    onCompletion() 
} 
+0

Это гораздо более ясное спасибо. Доступ к ServiceResponse осуществляется из методов NSURLConnectionDelegate, поэтому он добавлен. Нам придется реорганизовать класс, чтобы удалить их, но это, вероятно, будет нашим подходом. Благодарю. – Leon

+0

@ Leon: Вы всегда приветствуете друзей :) –

+0

Привет, @Leon, предлагаемый подход будет работать отлично, если использовать API-интерфейс на основе блоков для создания сетевого подключения (например, API NSURLSession на основе блоков). Если вы хотите работать с шаблоном делегата, я думаю, вы не можете избежать блокировки завершения. – BangOperator

1
VCA sends request A 
VCB sends request B 
Response B is returned to VCB 
Response A is returned to VCA - this causes an exception 

Так как ППГ и VCB использует тот же callwebservicelwith обновления VCB завершения блок VCA с завершения блока VCB.

Когда VCB получает данные, он хорошо отправляется в VCB, но затем, когда ответ VCA получен, вызывается блок завершения VCB.

И я полагаю, что VCB пытается проанализировать данные для ответа VCA, это вызывает проблему.

Вам необходимо обновить модель.


С минимальными изменениями в виду, вы можете отказаться от одноэлементных и использовать различные примеры для различных View Controllers. (Как указано на 4oy)

Есть много Lib третьей стороны, чтобы помочь вам в этом что касается.

Смежные вопросы