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

21 мар. 2014 г.

Добавить N-дней к NSDate

Есть два метода для достижении этой цели. Первый, является быстрым и немного грязноватым. И второй, который более безопасен в расчетах.
Первый способ включает в себя просто добавление количества дней в секундах:

NSDate *now = [NSDate date];
int daysToAdd = 50;  // или 60 :-)
NSDate *newDate1 = [now addTimeInterval:60*60*24*daysToAdd];
NSLog(@"Быстрый расчет: %@", newDate1);

Данный метод имеет ряд ограничений. Он не заботиться о переходе на летнее или зимнее время. Таким образом, Вы обходите границы DST, в конечном итоге получите результат, который расходится между желаемым результатом вычисления на один час и в худшем случае на день.
Таким образом, следующий метод использует класс NSDateComponents и григорианский календарь, чтобы правильно добавить количество дней и корректно рассчитать результат:

NSDate *now = [NSDate date];
int daysToAdd = 50;  // или 60 :-) 
// используем NSDateComponents
NSDateComponents *components = [[[NSDateComponents alloc] init] autorelease];
[components setDay:daysToAdd];
 
// Используем календарь
NSCalendar *gregorian = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
 
NSDate *newDate2 = [gregorian dateByAddingComponents:components toDate:now options:0];
NSLog(@"Правильный расчет: %@", newDate2);

Функции даты в Objective-C являются чрезвычайно мощными, но время от времени их трудно понять, для людей, которые являются начинающими программистами.

Конвертация NSString в массив символов

Один из способов сделать это - просто получить один символ подстроки из заданной полной строки:

NSString *s = @"Hello World";
int i;
NSMutableArray *m = [[NSMutableArray alloc] init];
 
for (i = 0;i < [s length]; i++) {
    [m addObject:[s substringWithRange:NSMakeRange(i, 1)]];
}
 
NSLog([m description]);

20 мар. 2014 г.

Добавление числа в массив / Add number to Array

Обычно в массив типа NSArray или NSMutableArray нельзя добавить простое число или структуру, а только объект. Значит (в нашем примере) преобразуем наше простое число (например int) в объект. Число можно преобразовать как с помощью NSString, так и с помощью NSNumber.

NSMutableArray *myArray = [NSMutableArray arrayWithCapacity:30]; // должен быть мутабельным
 
for (int x = 0; x < 30; x++) {
    // добавить как NSString
    [myArray addObject:[NSString stringWithFormat:@"%d", x]];
 
    // добавить как NSNumber
    [myArray addObject:[NSNumber numberWithInt: x]];
}
 
// результат
NSLog([myArray description]);

Для обоих случаев используемые классы возвращают число как объект.

NSString удаление пробелов в начале и конце текста

Удаление ненужных пробелов по бокам текста:

NSString *string = @" spaces in front and at the end ";
NSString *trimmedString = [string stringByTrimmingCharactersInSet:
                                  [NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSLog(trimmedString)

Хотя такая стандартная задача может выглядеть с чрезмерно большим количеством кода,но при этом Вы получаете множество дополнительных функций для операций с текстом. NSCharacterSet и его набор некоторых методов:

- alphanumericCharacterSet
- capitalizedLetterCharacterSet
- controlCharacterSet
- decimalDigitCharacterSet
- decomposableCharacterSet
- illegalCharacterSet
- letterCharacterSet
- lowercaseLetterCharacterSet
- newlineCharacterSet
- nonBaseCharacterSet
- punctuationCharacterSet
- symbolCharacterSet
- uppercaseLetterCharacterSet
- whitespaceAndNewlineCharacterSet
- whitespaceCharacterSet

18 мар. 2014 г.

Badges на иконке Вашего приложения (дополнение) / NSlider and docTile

Дополнение к статье заключается в том чтобы в реальном времени изменять данные в бэйджике на иконке приложения вместе с некими изменениями данных в Вашем приложении.

Нужно добавить в методе - (void)applicationDidFinishLaunching:(NSNotification *)aNotification строчку после [sliderTextLabel setIntValue:[slider intValue]]; :

[[NSApp dockTile] setBadgeLabel:[NSString stringWithFormat:@"%i",[slider intValue]]];

Эта строка проинициализирует начальное состояние числового значения слайдера и выведет его в бейдж.


Также в нашем экшене - (IBAction)sliderChange:(id)sender после строки [sliderTextLabel setIntValue:[slider intValue]]; Вставить ту же строку, что Вы вставляли в - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 

При изменении положения ползунка, данные будут меняться и в нашем бэйдже. Код:

[NSString stringWithFormat:@"%i",[slider intValue]]

приводит целочисленное значение в тип "строка", тем самым обрезает плавающую точку. Если вместо этого написать просто [slider stringValue], то будет отображаться число с плавающей точкой.

17 мар. 2014 г.

16 мар. 2014 г.

15 мар. 2014 г.

KVC (Key-Value Coding) Ключ - Значение

Ключ-значение кодирования представляет собой механизм для доступа к свойству объекта косвенно, с помощью строк для идентификации свойств, а не через вызов аксессора или доступ к ним непосредственно через переменных экземпляра. Что это значит. Допустим у Вас есть таблица с множеством колонок, каждое имя колонки можно превратить в ключ и обращаться по ключу вместо индекса колонки, ведь так проще, да и запомнить название колонки проще чем ее индекс.

В данном примере мы не будем работать с таблицами, а реализуем некий класс Books (Книги). Основное что нам требуется для книги это "Автор книги", "Название книги" и "Количество страниц в книге".


Итак добавили новый класс наследованный от NSObject:

Books.h :

#import <Foundation/Foundation.h>

@interface Books : NSObject

@property (strong) NSString *bookAuthor;
@property (strong) NSString *bookName;
@property int pageCount;

@end

Books.m - оставим пустым, т.к. остальное мы реализуем в классе AppDelegate

#import "Books.h"

@implementation Books

@end

В AppDelegate.h создадим массив booksArray со списком книг. Ведь у нас будет не одна книга. Также не забудем подключить наш класс Books.

#import <Cocoa/Cocoa.h>
#import "Books.h"

@interface AppDelegate : NSObject <NSApplicationDelegate> {
    NSMutableArray *booksArray;
}

@property (assign) IBOutlet NSWindow *window;
- (IBAction)printListBooks:(id)sender;

@end

На нашу форму поместим кнопку и сделаем связь кнопки с методом printListBooks.

В AppDelegate.m создадим несколько объектов книг и добавим их в массив который будет хранить список наших книг.

#import "AppDelegate.h"

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    
    booksArray = [[NSMutableArray alloc] init];
    
    // Добавляем наши книги-объекты в массив обычным способом
    
    Books *firstBook = [[Books alloc] init];
    [firstBook setBookAuthor:@"Т.Г. Шевченко"];
    [firstBook setBookName:@"Кобзарь"];
    [firstBook setPageCount:283];
    
    [booksArray insertObject:firstBook atIndex:[booksArray count]];
    
    Books *secondBook = [[Books alloc] init];
    [secondBook setBookAuthor:@"И. Франко"];
    [secondBook setBookName:@"Городские повести"];
    [secondBook setPageCount:478];
    
    [booksArray insertObject:secondBook atIndex:[booksArray count]];
}

Организуем код для кнопки, которая будет выдавать список объектов из массива книг.

- (IBAction)printListBooks:(id)sender {
    
    for (Books *currentBook in booksArray) {
        NSLog(@"Книга: %@, Автор книги: %@, К-во страниц: %i",
              [currentBook bookName],
              [currentBook bookAuthor],
              [currentBook pageCount]);
    }
}
@end

Запустим и получим результат:


А как же KVC ? Все довольно просто. Добавим еще одну книгу, но теперь будем обращаться не к переменным нашего объекта, а по ключу (аналогично названию переменным) и будем задавать ему значение:

 // Добавляем наши книги-объекты с помощью ключей (KVC)
    
    Books *threeBook = [[Books alloc] init];
    [threeBook setValue:@"Леся Украинка" forKey:@"bookAuthor"];
    [threeBook setValue:@"Боярыня" forKey:@"bookName"];
    [threeBook setValue:@"184" forKey:@"pageCount"];
    
    [booksArray insertObject:threeBook atIndex:[booksArray count]];

Здесь bookAuthor, bookName, pageCount являются ключами, а Value - значениями для каждого ключа. Запустим наше приложение:


Результат - добавлена третья книга в массив-список книг с помощью KVC.

10 мар. 2014 г.

NSSlider "ползунок"

Объект NSSlider отображает диапазон значений для чего-то (какого-нибудь контрола) в приложении. Ползунки могут быть вертикальными или горизонтальными полосами или круговыми циферблатами.

Создадим форму и расположим на ней некоторые контролы интерфейса:

Добавим:
- Label;
- Slider.

В Label установим текст со значением 50 (можно любое другое или вообще никакого текста на изменять, далее будет понятно почему). Добавим слайдер, выровняем, и сделаем наши связи со соледующими оутлетами:

IBOutlet NSTextField *sliderTextLabel;
IBOutlet NSSlider *slider;

Также добавим экшен на наш слайдер, который будет срабатывать при изменении ползунка слайдера:

- (IBAction)sliderChange:(id)sender;

В метод applicationDidFinishLaunching добавим следующий код инициализации нашего слайдера и нашего лейбла:

[slider setIntValue:50];
[sliderTextLabel setIntValue:[slider intValue]];

Можно установить любое значение слайдеру при инициализации. Дальше в нашем экшене-методе sliderChange напишем такие строчки кода:

[sliderTextLabel setIntValue:[slider intValue]];

При изменении местоположения ползунка будет меняться значение нашего лэйбла. Но есть один нюанс. Значение в лэйбле устанавливается (текущего значения слайдера) только тогда когда Вы остановили перемещение ползунка. Но нам бы хотелось пойти дальше и сделать более правильно, т.е. чтобы значение лэйбла менялось в реальном времени во время перемещения ползунка слайдера. Для этого нужно в Дизайнере форм пометить слайдер и в Инспекторе аттрибутов в секции Control выставить чекбокс Continuous. Вот и все.

NSPopupButton выпадающий список

Класс NSPopUpButton определяет объекты, которые реализуют всплывающее окно и ниспадающие меню, в графическом интерфейсе пользователя.

Создадим форму, на которой расположим наши контролы интерфейса:

- PopUpButton;
- TextField;
- Button;
- Label.

Сделаем связи наших контролов с нашими аутлетами и экшенами:

IBOutlet NSTextField *textLabel; // к Label
IBOutlet NSTextField *textField; // к TextField
IBOutlet NSPopUpButton *popUpButton; // к popUpButton


- (IBAction)addItemToPopUpButton:(id)sender; // к кнопке "Добавить"
- (IBAction)itemPopUpButtonDidSelected:(id)sender; // к popUpButton

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


- (IBAction)addItemToPopUpButton:(id)sender {
    
    if (![[textField stringValueisEqual: @""]) {
        [popUpButton addItemWithTitle: [textField stringValue]];
    }
}

- (IBAction)itemPopUpButtonDidSelected:(id)sender {
    
    [textLabel setStringValue:[popUpButton titleOfSelectedItem]];
}

Наш результат:
Теперь когда мы введем текст в TextField - поле и нажмем кнопку добавить, то наш текст будет добавлен в выпадающий список элемент за элементом. Если мы выберем какой-то элемент из выпадающего списка, то этот текст отобразится в нашем Label.

9 мар. 2014 г.

StatusBar приложение

Простой пример приложения которое имеет свое меню в статус баре OS X.

Создадим новый проект в Xcode. Перейдем в Interface Builder и добавим до нашего созданного окна "меню" (Выберем в списке контролов интерфейса Menu и положим где-то рядом с окном.
Отредактируем элементы списка меню:

- Показать окно;
- Выход.

В AppDelegate.h добавим следующие строки:

IBOutlet NSMenu *statusBarMenu;
NSStatusItem *statusBarItem;

- (IBAction)showWindow:(id)sender;
- (IBAction)quitApp:(id)sender;

Соединим наш оутлет NSMenu с нашим добавленным меню. Наши экшены соотвествующими элементами меню.

В AppDelegate.m в методе awakeFromNib напишем следующий код:

statusBarItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
[statusBarItem setMenu:statusBarMenu];
[statusBarItem setTitle:@"МоеМеню"];
[statusBarItem setHighlightMode:YES];

В экшене showWindow пишем следующее:

[NSApp activateIgnoringOtherApps:YES];
[_window makeKeyAndOrderFront:nil];

Код будет показывать нам наше скрытое приложение, будь оно свернуто или закрыто.

В экшене quitApp пишем:

[NSApp terminate:nil];

Ну вот и все.
Также можно добавить иконку к нашему меню. Если убрать setTitle, то у нас будет вместо надписи в статус баре только иконка. Иконка должна быть соотвествующих размеров как для обычных экранов так и для ретина-экранов.


8 мар. 2014 г.

Установить бэйдж на иконку приложения с помощью Objective-C

Для быстрой установки бэйджа на иконку своего приложения можно с помощью метода NSDockTitle.

[[NSApp dockTile] setBadgeLabel:@"МойБэйдж"];

Это покажет красный бэйдж на иконке Вашего приложения. Но нужно помнить одну вещь. Сообщение будет показано полностью если текст сообщения не будет длиннее чем ширина иконки приложения.

Здесь видно что текст отображается полностью и нигде не обрезан.



А вот тут уже другая история. Середина текста выковыряна, т.к. текст больше чем сама ширина иконки.

18 февр. 2014 г.

Метод KeyDown - определение нажатых клавиш

На вход метода keyDown поступает событие NSEvent, которое будет обозначать код нажатой клавиши. Нам остается лишь сверить код поступившей в переменную нажатой клавиши.


- (void)keyDown:(NSEvent *)theEvent
{
    NSString *chars = theEvent.charactersIgnoringModifiers;
    unichar aChar = [chars characterAtIndex: 0];
    
    // F5
    if (aChar == 63240)
    {
        // что-то делаем
    }
    
    // F6
    if (aChar == 63241)
    {
        // что-то делаем
    }
    
        // что-то делаем другое
}

15 февр. 2014 г.

Урок по работе с NSTableVIew. Добавление данных

Для пользователя очень важно, чтобы данные были представлены в удобном виде. В этой статье мы рассмотрим как создается табличное представление данных в OS X. Урок предназначен для тех кто уже более-менее знаком с Objective-C, и протоколами. Для начала создадим новый проект в Xcode (Cocoa). Назовем его, например, TableViewAddDataTest. Добавим на нашу форму TableView контрол. Выставим размеры согласно нашей форме (окну).



Установим количество колонок в таблице равным 1-й (Attribute Inspector -> Columns). Дальше заходим в Connections Inspector и соединяем (делаем связь) нашему аутлету dataSource и делегату delegate с AppDelegate.

А теперь о главном. "Нельзя просто так взять и добавить строчку в таблицу напрямую", проще всего и быстрее будет пакетная передача объектов таблице, что чаще в роли пакетов объектов выступают массивы, в нашем случае NSArray (для одной колонки).

И так - поехали. В наш хидер-файл AppDelegate.h добавим протокол (делегат), объявим наш массив dataArray и объект myTableView через который будем работать с таблицей и будем использовать методы NSTableView класса:

//
//  AppDelegate.h
//  TableViewAddDataTest
//
//  Created by Sergey Krasiuk on 15.02.14.
//  Copyright (c) 2014 Sergey Krasiuk. All rights reserved.
//

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate, NSTableViewDataSource>
{
    NSArray *dataArray;
    NSTableView *myTableView;
}

@property (assign) IBOutlet NSWindow *window;

@end

Главное что нужно помнить при работе с табличным представлением, это - два обязательных метода, без которых в таблице не появятся данные:


//  Нужно передать табличному представлению количество строк
//  для отображения данных, в нашем случае это колличество элементов в массиве.
- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView


//  Возвращает объект (данные которые будут отображаться в строке)
//  для каждой строчки row нашего табличного представления
- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row

А теперь понятным языком. В первый метод мы должны передать количество объектов в нашем массиве. На основе этого в таблице будет выделена память под каждую строчку:


- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
{
    return [dataArray count];
}

Следующий шаг. Мы должны передать для каждой строчки таблицы данные которые хранятся в нашем массиве. Т.е. человеческим языком индекс строки row будет равен индексу элемента нашего массива данных. В нашем случае мы передадим объекты типа NSString для каждой строки:


- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
    NSString *arrayString = [dataArray objectAtIndex:row];
    return arrayString;
}


Проинициализируем наш массив (заполним его данными), т.к. пока что передавать нам в таблицу нечего (лучше всего инициализацию делать в методе init (в нашем случае), не в applicationDidFinishLaunching, при запуске массив не успеет заполнится данными и мы в таблице ничего не получим):


- (id) init
{
    self = [super init];
    
    if (self)
    {
        dataArray = [[NSArray alloc] initWithObjects:@"Первая строка", @"Вторая строка", @"Третья строка", @"Четвертая строка", @"Пятая строка", @"Шестая строка", nil];
    }
    
    return self;
}

Запускаем наш проект, и должно получится вот такое:
Нюанс в добавлении или удалении элементов (строк) из таблицы состоит в том чтобы вычислить выделенный объект (строку таблицы) и получить его индекс. Потом удалить/добавить объект под этим индексом из/в массива и вызвать в том же методе (в котором удаляем/добавляем объекты из массива) reloadTable. Табличное представление обновит данные из массива и покажет нужный результат:

- (void) tableViewSelectionDidChange: (NSNotification *) notification

Удачи в начинаниях. Еще один из примеров NSTableView


13 февр. 2014 г.

Меняем стандартный курсор на иконку

Код который меняет стандартный курсор (стрелку) Вашего приложения (контрола в приложении, например NSView) на картинку или иконку.

- (void)resetCursorRects
{
    int crossCursorHeight = 38;
    int crossCursorWidth = 38;
    NSString *imageName = [[NSBundle mainBundle] pathForResource:@"cursor-std" ofType:@"png"];
    NSImage *cross_cursor = [[NSImage alloc] initWithContentsOfFile:imageName];
    [cross_cursor setSize:NSMakeSize(crossCursorWidth, crossCursorHeight)];
    NSCursor *customCursor = [[NSCursor alloc] initWithImage:cross_cursor 
                                       hotSpot:NSMakePoint(crossCursorWidth / 2, crossCursorHeight / 2)];
    [self addCursorRect:[self bounds] cursor:customCursor];
}

10 июн. 2013 г.

Простой пример NSTableView приложения с NSArrayController и NSUserDefaultsController

Сегодня я опишу один из простых примеров, который уже достал меня и забрал много времени, когда я пытался его реализовать! Я покажу Вам, как выполнить связь между NSTableColumn, NSArrayController и NSUserDefaultsController, не написав ни единой строчки кода.

Шаг 1: Создайте новый Cocoa-проект
Шаг 2: Дизайн ГУИ.

    Выберите MainMenu.xib, перетащите кнопки и таблицу из библиотеки объектов на окно и расставьте их в соотвествии как показано на скриншоте. Также добавьте из библиотеки объектов объект Array Controller, на панель xib. В моем случае я его переименовал в playersArrayController, который видно на скриншоте.

Шаг3: В окне настроек объектов (справа), выбираем меню Content Array binding. (Не забудьте включить состояние флажка на "Handles Content As Compound Value"



Шаг 4: Выставьте значение имени столбца Player (Model Key Path), в соответствии с рисунком ниже.


Шаг 5: И также для имени столбца Sport (Model Key Path), в соответствии с рисунком ниже.


Шаг 6: Свяжем действие add кнопки "+" с нашим Array Controller`ом.


Шаг 7: Такое же действие remove для кнопки "-" с нашим Array Controller`ом.


Шаг 8: Кнопку "Save" свяжем с действием Shared User Defaults Content.


    Финальный шаг - запустите программу. Теперь попробуйте в действии "+" и "-". Добавятся строки которые можно редактировать. А при нажатии на кнопку "Save", данные сохранятся. И после перезапуска приложения данные снова появятся в таблице.
 

    Пример кода можно скачать с github.com
    P.S. От автора. Переведенная статья, найдена на просторах сети.