1. Objective C / Говнокод #12457

    −101

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    - (void)viewDidLoad
    {
        // ...
        
        float os_verson = [[[UIDevice currentDevice] systemVersion] floatValue];
        NSString* dev_ver_str = [[UIDevice currentDevice] systemVersion];
        
        if (os_verson >= 4 || [dev_ver_str hasPrefix:@"3.2"]) {
            [self viewWillAppear:NO];
            [self viewDidAppear:NO];
        }
    }

    Костыли наше всё

    Запостил: tyler, 21 Января 2013

    Комментарии (53) RSS

    • А зачем автор такого нагородил? Чего он этим добивался?
      Ответить
      • К нам этот проект прилетел на доработку на прошлой неделе, так что сами еще не поняли всех замыслов автора. Ждите апдейтов)

        например вот:

        [[self parentViewController] performSelector:@selector(dismissModalVi ewController) withObject:nil afterDelay:0.0001];

        что он курил, я не знаю
        Ответить
        • Это "щастье" будет положено в очередь сообщений и выполнится сразу после выхода из метода... Ищите что-то в месте, вызывающим функцию, в которой эта строка находится. (Да, у меня с Квикником большой опыт телепатии...)
          Ответить
        • afterDelay это святое, спасал меня не раз =)
          Надо только afterDelay:0 делать. Ну а сейчас проще через GCD.
          Ответить
          • Сгинь, говнокодер. Расстреливать таких надо, цинично и жестоко :D
            Ответить
            • Расстрел - это слишком.
              Берите пример с гуманизма Российской империи. Никакой смертной казни. Максимум - 12000 шпицрутенов.
              Ответить
              • Ты так и не просёк фишку.
                Смысл расстрела не уменьшении числа говнокодеров. а в удовлетворении садистских наклонностей расстреливающего. Я хочу видеть ужас в глазах провинившегося :)
                Ответить
                • Почему бы тогда не предать говнокодера милостивой смерти без пролития крови (сжечь на костре)?
                  Ответить
                  • Не, там в глаза не посмотреть. А я именно хочу ужас увидеть, а не услышать вопли.
                    Ответить
                    • Интересное допущение фантазии: можно говнокодерам назначать любую казнь, но не всегда можно посмотреть в глаза.
                      Ответить
                • Когда я озвучил твою методику повышения качества кода, то программисты наши заявили, что у тебя суицидальные наклонности :)
                  Ответить
                  • Я уже отвечал на это - говна в мой код вставили, а потом я ещё и крайний. Ибо уволился. и на меня можно спихнуть. Ни один из приведённых тобой примеров "моего" говнокода мной написан не был.
                    Ответить
                    • > говна в мой код вставили
                      Гражданин начальник, мне эти наркотики подбросили!
                      Ответить
                      • Этот спор уже был, не вижу смысла продолжать.
                        Ответить
                    • - Поручик, у вас сюртук заблёван.
                      - Это ик... корнет Оболенский на балу... ик... подбежал ко мне и как наблюёт на меня!
                      - Да он вам и в штаны насрал...
                      Ответить
            • ой, да ладно. Отложить на ранлуп - еще со времен WinForms все так делают. Видел у очень крутых программистов.

              А отложить анимацию на 0,3 тоже нормально. Как еще сделать закрытие модального контроллера, а после этого сразу открытие нового с анимацией. Или поп и пуш в навигейшне оба с анимацией. У них же нет action на конец анимации.

              Так что это вполне нормальный интерфейсный код :)
              Ответить
              • Не у нас одних внедряются извращённые дизайнерские идеи.
                Ответить
              • Вот только пул должен не сам модифицировать интерфейс, а слать события обратно в UI тред.
                Ответить
                • Так если мы сейчас в главном потоке, то и выполнится performSelector:withObject:afterDelay в главном. Разве нет?
                  Ответить
                  • Я не iOS разработчик и могу не знать тонкостей, но вполне вероятно, что это ведёт к сабмиту таски в пул. В текущем потоке это может выполняться только в том случает, если performSelector засыпает до тех пор, пока не выполнится задача, т.е. это эквивалент Thread.sleep(someTime); doIt();
                    Ответить
                    • Не, тут засыпания потоков нет. NSRunLoop - это родственник андроидовского Looper.
                      Ответить
                      • Если он сабмиттит таску в очередь сообщений, разгребаемую тем же потоком, то ничего против не имею.
                        Ответить
              • Хз хз, ни разу не возникло необходимости использовать afterDelay с нулевым значением. Анимации и те можно задержать средствами самой анимации.
                На тему вполненормальности - не соглашусь ещё раз, делал то же самое без задержек. Если уж очень захотелось сделать что-то, для чего не хватает данных при запуске анимации - прицепитесь к колбеку. А то захотите время анимации поменять, и привет.
                Ответить
                • А на тему "Видел у очень крутых программистов" - а мозг на что дан? Если бы я исключительно смотрел как делают " крутые программисты" - я бы не умел очень многих вещей.
                  Ответить
                  • Глянуть, как делает профессионал, - это один из способов самообразования. Не единственный, а один из. Не утрируй.
                    Ответить
                    • Это ты не утрируй.
                      Ты путаешь способ обучения и аргумент для принятия решения.
                      Ответить
                • Так нет колбеков у многих анимаций (см. выше), а время можно в константы выносить, тогда менять проще. Эппл так же делает, есть константы для времени анимаций.

                  afterDelay:0, насколько я помню, еще помогает, если у нас идет скролл scrollView, а что-то хочется в главном потоке сделать, чтобы скролл не тормозил. Откладываем и наслаждаемся.
                  Ответить
                  • Можно реальный пример? Что то вы такое фантастическое загнули.
                    Ответить
                    • Поискал по проектам. Про scrollView не нашел, может приснилось...

                      Вот, например, по-мойму вполне нормальный код. Если на экране несколько полей, и нам надо перестраивать view в зависимости от того, видна клавиатура или нет, то когда с одного поля переключается на другой - дергается перестраивание (вызывается end, потом сразу begin). А если отложить - отлично работает. Если писать по-честному - будет в три раза длинее и менее красиво.

                      #pragma mark - UITextFieldDelegate
                      
                      - (void)textFieldDidBeginEditing:(UITextField *)textField
                      {
                          // чтоб не дергалось слегка откладываем
                          [self performSelectorAfterRunLoop:@selector(layoutAnimated)];
                      }
                      
                      - (void)textFieldDidEndEditing:(UITextField *)textField
                      {
                          // чтоб не дергалось слегка откладываем
                          [self performSelectorAfterRunLoop:@selector(layoutAnimated)];
                      }


                      В остальном - это все откладывание, чтобы анимации не накладывались или типо того.
                      Ответить
                      • Так, вы меня поймали на том, что я НЕ делал. Пошёл вкуривать. В других DidЧто-то я таких проблем не видел. Какая версия iOS?
                        Ну и это не тот performSelector, о котором шла речь. Единственное приемлемое использование из вcех вариантов, что я видел для performSelector:withObject:afterDelay: - скрытие сплэш-скрина.
                        Ответить
                        • Пример тоже почти нормальный (только я бы 0.0001 на 0 поменял). dismissModal вполне может хотеться отложить из-за какой-то анимации или типо-того.

                          Как я понял тут все вообще против использования afterDelay на интерфейсе. Я вот и защищаю.

                          Я без вот этой функции жить не могу:

                          void doAfter(CGFloat delay, BasicBlock action)
                          {
                              dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), dispatch_get_current_queue(), action);
                          }


                          Можно писать вот так:

                          doAfter(0.2, ^{
                              // bla bla bla
                          });


                          В последнем проекте на 1 человеко-месяц 17 использований :)
                          Ответить
                          • То, что их 17 - это ещё не значит, что это хорошо )
                            Ответить
                      • - (void)textFieldDidBeginEditing:(UITextField *)textField
                        {
                            [UIView animateWithDuration:0.3 animations:^{
                                [textField setFrame:CGRectMake(10, 210, 200, 32)];
                            }];
                            
                        //    [UIView beginAnimations:nil context:nil];
                        //    [textField setFrame:CGRectMake(10, 210, 200, 32)];
                        //    [UIView commitAnimations];
                        }
                        
                        - (void)textFieldDidEndEditing:(UITextField *)textField
                        {
                            [UIView animateWithDuration:0.3 animations:^{
                                [textField setFrame:CGRectMake(10, 410, 200, 32)];
                            }];
                        
                        //    [UIView beginAnimations:nil context:nil];
                        //    [textField setFrame:CGRectMake(10, 410, 200, 32)];
                        //    [UIView commitAnimations];
                        }


                        Оба варианта анимации работают нормально, ищите баги в проекте
                        Ответить
                        • layout еще должен зависить от того, видна клавиатура или нет. Вот набросал примерчик: https://github.com/pilot34/TestAfterDelay

                          Там если кликаем на фон - клавиатура пропадает. Воспроизводится глюк так: кликаем на одно поле, потом переключаем на другое - дергается.
                          Ответить
                          • Нет, вы таки говнокодер :)

                            Замените в вашем проекте метод layoutAnimated на следующий

                            - (void)layoutAnimated
                            {
                                    [UIView animateWithDuration:0.3
                                                          delay:0
                                                        options:UIViewAnimationOptionBeginFromCurrentState
                                                     animations:^{
                                                                 [self layout];
                                                     } completion:nil];
                            }


                            или без блока, что мне нравится больше (нужный метод в форме блока слишком длинный):

                            - (void)layoutAnimated
                            {
                                [UIView beginAnimations:@"kbLayout" context:nil];
                                [UIView setAnimationBeginsFromCurrentState:YES];
                            
                                [self layout];
                            
                                [UIView commitAnimations];
                            }


                            и наслаждайтесь ;)
                            Ответить
                            • Вообще, я бы использовал 2й вариант, потому что запуск 2й анимации с таким же именем как у 1й останавливает предыдущую копию, если не ошибаюсь.
                              Ответить
                              • о, какая крутотенюшка, не зря целый день спорили, узнал что-то новое, спасибо.
                                Ответить
                                • То, что стоит знать об анимации:
                                  Все переменные после запуска анимации переходят в состояние конечной точки анимации. Дальше меняется только картинка. Запуская анимацию по тем же свойствам, что уже анимируются - вы обрываете анимацию свойств старую.

                                  В данном случае работало всё это так:
                                  При выборе первого поля запускалась анимация и перемещала поля вверх.
                                  Про выборе 2го поля происходило сразу 2 события друг за другом - endEditing и beginEditing
                                  В endEditing запускалась анимация, перемещения полей вниз, но сразу за ней прилетала 2я анимация на те же свойства - перемещение полей вверх. 1я - изменяла состояния переменных, но завершится не успевала. 2я же работала уже целиком, от нижней позиции, выставленной первой.

                                  Опция же BeginFromCurrentState делает ровно то, что написано в её названии - говорит CoreAnimation, что в качестве стартового значения надо использовать текущее состояние анимируемой картинки, а не старые значения свойств. Двойной вызов это не убирает, но избавляет от глюков.

                                  А как работало ваше решение, я даже не представляю, могу предположить только race condition.
                                  Ответить
                                  • Да, то что нужно, спасибо.

                                    В моем случаем layout откладывался до момента, когда курсор уже установился во второе поле. Поэтому он отрабатывал оба раза как надо (обе анимации делали одно и то же).
                                    Ответить
                                    • А, ну да. Там же условие внутри. Пол третьего ночи дают о себе знать )
                                      Ответить
                                    • Кстати, о птичках. Очерёдности сообщений я бы тоже не доверял. Самолично воспроизводил глюк (в эмуляторе и на устройстве), когда от UIScrollView сначала приходил scrollViewDidEndDragging с willDecelerate = NO, а буквально следом за ним - scrollViewDidScroll.
                                      К стыду своему я не нашёл другого решения, кроме как обрабатывать scrollViewDidEndDragging с задержкой в 0.05 сек )
                                      Ответить
                          • Вообще, это та причина, по которой я и не люблю такое использование performSelector - это всегда обход не выловленной ошибки или пробела в знаниях программиста
                            Ответить
                            • Эпическая правка крэша NSLog*ом на Хабре)
                              Ответить
                              • Не знаю, мне почему-то вспомнились наши тестеры, которые в течении кучи версий пропускали анимацию панелей в стиле "кровь кишки распидорасило", но когда я увидел этот код, схватился за голову и вылизал вьюху и анимации - мне вернули баг - они рассмотрели, что я ошибся на 0.1 мс с продолжительностью анимаций, "раньше было нормально"...
                                Ответить
                • Фантазия заказчика неистощима. А знания программистов имеют предел.
                  Ответить
        • Доработка, да.
          Тут бы переписать нафиг.
          Ответить
          • Примерно раз в 10 минут ловлю себя на этой мысли (
            Ответить
            • Когда переписывал код одного уникума, функции у меня уменьшались в 10 раз. У вас такое есть?
              Ответить

    Добавить комментарий