Страницы

Поиск по вопросам

Показаны сообщения с ярлыком cocoa. Показать все сообщения
Показаны сообщения с ярлыком cocoa. Показать все сообщения

воскресенье, 26 января 2020 г.

Последовательность запуска приложения, написанного на Cocoa

#cocoa #xcode #macos


Скачал исходный код торрент-клиента Transmission для изучения. Пытаюсь идти по цепочке,
и если я правильно все понял, то:

Как и у всех C-подобных программ,
    запуск начинается с функции main()
Далее, отсюда функция
        NSApplicationMain()  запускает
        обработчик (цикл) сообщений, которые
        будут поступать из файлов .xib
?
            - и здесь моя цепочка обрывается

В каком месте программа продолжается? Нет нигде ни AppDelegate, ни реализации протокола
NSApplicationDelegate. Не могу уцепиться - выйти из функции main() - куда мне последовательно
идти? Какой файл дальше просматривать? Файл .xib с окном, которое появляется первым
при запуске программы, я нашел. Но откуда программа его запускает?    


Ответы

Ответ 1



Отвечу на вопросы в обратном порядке. Программа запускает файл с окном из main bundle приложения. Это происходит в функции NSApplicationMain. В случае Transmission этот самый .xib - это MainMenu.xib. Затем стоит просмотреть файл Controller.h. У главного окна приложения через IBOutlet указан экземпляр класса Controller - значит, этот класс будет инстанцирован уже в функции NSApplicationMain. Перед посылкой классу любого другого сообщения будет послано сообщение +initialize, начинать читать можете с него. После этого будет послан обычный alloc-init, читаете, что происходит в init. После переходите к awakeFromNib, который вызывается после инициализации объекта, загруженного из nib-файла. Только после этого NSApplicationMain создаст главный NSRunLoop приложения, который, как вы сказали, будет принимать события от пользовательского интерфейса.

воскресенье, 22 декабря 2019 г.

Множественное выделение строк в UITableView

#cocoa #objective_c #ios


Как реализовать multi-selection в UITableView?    


Ответы

Ответ 1



По умолчанию, UITableView поддерживает режим выбора только одной строки. Но можно создать свой multi-selection в UITbaleView. Чтобы таблица имела возможность множественного выбора нужно поставить стиль стандартного выделения "none" и самостоятельно отслеживать события и менять вид элементов. Для этого следует выполнить несколько шагов: Пусть на верхней панели таблицы есть кнопка "Edit", которая при переходе в edit-mode меняется на "Cancel". При переходе в режим редактирования снизу таблицы появляется панель инструментов с вариантами действий над элементами таблицы. Для обнаружения выделенных строк использовать метод tableView:didSelectRowAtIndexPath:. В этом методе мы будем добавлять только что выбранный элемент в коллекцию. Т.к. мы не можем полагаться на стандартный UITableView, мы должны создать коллекцию, содержащую выделенные в данный момент элементы. Также, при выборе элемента мы должны сменить фон элемента и отодвинуть его от левого края, чтобы поместить туда специальный индикатор выделения (наподобие checkbox). Панель инструментов нужно создать в методе viewDidLoad, добавив что-то подобное: actionToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 416, 320, 44)]; actionButton = [[[UIBarButtonItem alloc] initWithTitle:@"No Action" style:UIBarButtonItemStyleBordered target:self action:@selector(noAction:)] autorelease]; [actionToolbar setItems:[NSArray arrayWithObject:actionButton]]; Затем, в методе viewDidAppear мы можем добавить нашу панель инструментов в иерархию - (void)viewDidAppear:(BOOL)animated { [self.view.superview addSubview:actionToolbar]; } Стандартный режим редактирования для UITableView реализуется посредством вызова setEditing:animated:. Но т.к. Мы не собираемся использовать никакой из стандартных UITableViewCellEditingStyle, то вызов этого метода не является строго обязательным, но его можно будет использовать для уведомления UITableViewCell. Методы edit и cancel можно реализовать примерно так: - (void)edit:(id)sender { [self showActionToolbar:YES]; UIBarButtonItem *cancelButton = [[[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStyleDone target:self action:@selector(cancel:)] autorelease]; [self.navigationItem setRightBarButtonItem:cancelButton animated:NO]; [self updateSelectionCount]; [self.tableView setEditing:YES animated:YES]; } - (void)cancel:(id)sender { [self showActionToolbar:NO]; UIBarButtonItem *editButton = [[[UIBarButtonItem alloc] initWithTitle:@"Edit" style:UIBarButtonItemStylePlain target:self action:@selector(edit:)] autorelease]; [self.navigationItem setRightBarButtonItem:editButton animated:NO]; NSInteger row = 0; for (MultiSelectCellController *cellController in [tableGroups objectAtIndex:0]) { [cellController clearSelectionForTableView:self.tableView indexPath:[NSIndexPath indexPathForRow:row inSection:0]]; row++; } [self.tableView setEditing:NO animated:YES]; } Далее, при вызове setEditing у UITableView таблица вызывает setEditing у всех видимых элементов (UITableViewCell). Мы можем переопределить этот метод и использовать для перехода из режима в режим отдельно взятого элемента таблицы (показать или скрыть "галочку"). Проще всего это реализовать следующим образом: конкретно в методе setEditing мы инициируем relayout методом setNeedsLayout, а основной код поместим в layoutSubviews (теперь мы будем правильно перерисовывать элемент вне зависимости от того, что стало причиной перерисовки). - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [self setNeedsLayout]; } Можно непосредственно в layoutSubviews и добавлять сам рисунок "галочки". Но с точки зрения организации кода это не очень красивое решение, т.к. подразумевается, что UITableViewCell - это только макет элемента. Поэтому лучше добавлять галочку уже в UITableView, но это неважно. Итак, в layoutSubviews мы будем отодвигать элемент от левого края, чтобы освободить место для "галочки", вот так: - (void)layoutSubviews { [UIView beginAnimations:nil context:nil]; [UIView setAnimationBeginsFromCurrentState:YES]; [super layoutSubviews]; if (((UITableView *)self.superview).isEditing) { CGRect contentFrame = self.contentView.frame; contentFrame.origin.x = 40; // делаем отступ self.contentView.frame = contentFrame; } else { CGRect contentFrame = self.contentView.frame; contentFrame.origin.x = 0; self.contentView.frame = contentFrame; } [UIView commitAnimations]; } Теперь осталось только поставить cell.selectionStyle = UITableViewCellSelectionStyleNone т.к. мы не хотим использовать стандартный selection. Вместо этого надо просто менять backgroundView у элемента. P.s. Пример можно посмотреть в приложении Mail.

Ответ 2



В iOS5 этот функционал встроен. Достаточно в viewDidLoad указать self.tableView.allowsMultipleSelectionDuringEditing = YES; Пример кода от Apple. П.С.: кстати, оригинал статьи, на которой основан ответ CrazyWorld находится тут: Multiple row selection and editing in a UITableView (англ.)

воскресенье, 15 декабря 2019 г.

Типичные ошибки программирования на Objective-C [закрыт]

#ipad #cocoa #objective_c #ios #iphone


        
             
                
                    
                        
                            Closed. This question is off-topic. It is not currently
accepting answers.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Want to improve this question? Update the question so
it's on-topic for Stack Overflow на русском.
                        
                        Closed 4 года назад.
                                                                                
           
                
        
Расскажите общие ошибки, допущенные Objective-C разработчиками, которые вы знаете.
Как мы можем их избежать? В общем, хотелось бы увидеть ошибки связанные с управлением
памятью, анти-паттерны и любые другие ошибки программирования под iOS.
Пожалуйста, обоснуйте свой ответ, а также можно привести примеры.
Начну с одной известной ошибки. Это объявление нового класса без суперкласса, т.е.
предполагая, что он будет иметь суперкласс по умолчанию. Здесь важно помнить, что Objective-c
не поддерживает множественное наследование, НО поддерживает несколько корней. То есть
корень - это не обязательно только класс NSObject. Таким образом, если вы пишете
/* не имеет суперкласса, не делайте этого! */
@interface MyClass
@end

Вы объявляете новый корень, а не подкласс NSObject.
Все подклассы NSObject должны быть прописаны вот так:
/* суперкласс NSObject */
@interface MyClass : NSObject
@end
    


Ответы

Ответ 1



UIViews и UIViewControllers - разные вещи и не могут быть взаимозаменяемыми. Не каждый контроллер должен быть UIViewController. Жизненный цикл UIViewController. В частности вьюшка выгружается (unloaded) в ответ на memory warnings. Обычно это бывает, когда разработчик использует вьюшку для хранения данных. Результат - потеря данных.

Ответ 2



Эта ошибка относится не только для новичков Objective-C (но и для Java, например). То есть проблема общего понимания того, что пишешь. Сравнение через == str == @"Test" Вместо [str isEqualToString:@"Test"]

Ответ 3



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

вторник, 13 ноября 2018 г.

Множественное выделение строк в UITableView

Как реализовать multi-selection в UITableView?


Ответ

По умолчанию, UITableView поддерживает режим выбора только одной строки. Но можно создать свой multi-selection в UITbaleView. Чтобы таблица имела возможность множественного выбора нужно поставить стиль стандартного выделения "none" и самостоятельно отслеживать события и менять вид элементов. Для этого следует выполнить несколько шагов: Пусть на верхней панели таблицы есть кнопка "Edit", которая при переходе в edit-mode меняется на "Cancel". При переходе в режим редактирования снизу таблицы появляется панель инструментов с вариантами действий над элементами таблицы. Для обнаружения выделенных строк использовать метод tableView:didSelectRowAtIndexPath:. В этом методе мы будем добавлять только что выбранный элемент в коллекцию. Т.к. мы не можем полагаться на стандартный UITableView, мы должны создать коллекцию, содержащую выделенные в данный момент элементы. Также, при выборе элемента мы должны сменить фон элемента и отодвинуть его от левого края, чтобы поместить туда специальный индикатор выделения (наподобие checkbox). Панель инструментов нужно создать в методе viewDidLoad, добавив что-то подобное: actionToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 416, 320, 44)]; actionButton = [[[UIBarButtonItem alloc] initWithTitle:@"No Action" style:UIBarButtonItemStyleBordered target:self action:@selector(noAction:)] autorelease]; [actionToolbar setItems:[NSArray arrayWithObject:actionButton]]; Затем, в методе viewDidAppear мы можем добавить нашу панель инструментов в иерархию - (void)viewDidAppear:(BOOL)animated { [self.view.superview addSubview:actionToolbar]; } Стандартный режим редактирования для UITableView реализуется посредством вызова setEditing:animated:. Но т.к. Мы не собираемся использовать никакой из стандартных UITableViewCellEditingStyle, то вызов этого метода не является строго обязательным, но его можно будет использовать для уведомления UITableViewCell. Методы edit и cancel можно реализовать примерно так: - (void)edit:(id)sender { [self showActionToolbar:YES]; UIBarButtonItem *cancelButton = [[[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStyleDone target:self action:@selector(cancel:)] autorelease]; [self.navigationItem setRightBarButtonItem:cancelButton animated:NO]; [self updateSelectionCount]; [self.tableView setEditing:YES animated:YES]; }
- (void)cancel:(id)sender { [self showActionToolbar:NO]; UIBarButtonItem *editButton = [[[UIBarButtonItem alloc] initWithTitle:@"Edit" style:UIBarButtonItemStylePlain target:self action:@selector(edit:)] autorelease]; [self.navigationItem setRightBarButtonItem:editButton animated:NO]; NSInteger row = 0; for (MultiSelectCellController *cellController in [tableGroups objectAtIndex:0]) { [cellController clearSelectionForTableView:self.tableView indexPath:[NSIndexPath indexPathForRow:row inSection:0]]; row++; } [self.tableView setEditing:NO animated:YES]; } Далее, при вызове setEditing у UITableView таблица вызывает setEditing у всех видимых элементов (UITableViewCell). Мы можем переопределить этот метод и использовать для перехода из режима в режим отдельно взятого элемента таблицы (показать или скрыть "галочку"). Проще всего это реализовать следующим образом: конкретно в методе setEditing мы инициируем relayout методом setNeedsLayout, а основной код поместим в layoutSubviews (теперь мы будем правильно перерисовывать элемент вне зависимости от того, что стало причиной перерисовки). - (void)setEditing:(BOOL)editing animated:(BOOL)animated { [self setNeedsLayout]; } Можно непосредственно в layoutSubviews и добавлять сам рисунок "галочки". Но с точки зрения организации кода это не очень красивое решение, т.к. подразумевается, что UITableViewCell - это только макет элемента. Поэтому лучше добавлять галочку уже в UITableView, но это неважно. Итак, в layoutSubviews мы будем отодвигать элемент от левого края, чтобы освободить место для "галочки", вот так: - (void)layoutSubviews { [UIView beginAnimations:nil context:nil]; [UIView setAnimationBeginsFromCurrentState:YES]; [super layoutSubviews]; if (((UITableView *)self.superview).isEditing) { CGRect contentFrame = self.contentView.frame; contentFrame.origin.x = 40; // делаем отступ self.contentView.frame = contentFrame; } else { CGRect contentFrame = self.contentView.frame; contentFrame.origin.x = 0; self.contentView.frame = contentFrame; } [UIView commitAnimations]; } Теперь осталось только поставить cell.selectionStyle = UITableViewCellSelectionStyleNone т.к. мы не хотим использовать стандартный selection. Вместо этого надо просто менять backgroundView у элемента. P.s. Пример можно посмотреть в приложении Mail.

четверг, 25 октября 2018 г.

Типичные ошибки программирования на Objective-C [закрыт]

Расскажите общие ошибки, допущенные Objective-C разработчиками, которые вы знаете. Как мы можем их избежать? В общем, хотелось бы увидеть ошибки связанные с управлением памятью, анти-паттерны и любые другие ошибки программирования под iOS. Пожалуйста, обоснуйте свой ответ, а также можно привести примеры. Начну с одной известной ошибки. Это объявление нового класса без суперкласса, т.е. предполагая, что он будет иметь суперкласс по умолчанию. Здесь важно помнить, что Objective-c не поддерживает множественное наследование, НО поддерживает несколько корней. То есть корень - это не обязательно только класс NSObject. Таким образом, если вы пишете /* не имеет суперкласса, не делайте этого! */ @interface MyClass @end Вы объявляете новый корень, а не подкласс NSObject. Все подклассы NSObject должны быть прописаны вот так: /* суперкласс NSObject */ @interface MyClass : NSObject @end


Ответ

UIViews и UIViewControllers - разные вещи и не могут быть взаимозаменяемыми. Не каждый контроллер должен быть UIViewController. Жизненный цикл UIViewController. В частности вьюшка выгружается (unloaded) в ответ на memory warnings. Обычно это бывает, когда разработчик использует вьюшку для хранения данных. Результат - потеря данных.