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

2 июн. 2014 г.

ORB OS X Icon Pack by Luke O'Sullivan


ORB OS X Icon Pack by Luke O'Sullivan

New:
- Activity Monitor
- Airport Utility
- Bluetooth (File Exchange)
- Chess (!)
- Chrome (from Frost for OS X)
- Dictionary
- Disk Utility
- DropBox
- iConvert Icons
- Adobe Illustrator
- Adobe InDesign
- Mission Control
- OS X
- Adobe Photoshop
- Skype
- Spotify
- System Info
- Time Machine
- VLC

Original:
- App Store
- iLife (iMovie x2, GarageBand x2, iPhoto)
- Calendar (x2)
- Citrix Receiver
- Contacts
- Dashboard
- FaceTime
- Finder
- Font Book *updated*
- iBooks (now x2) *updated*
- Image Capture
- iTunes (in blue and red)
- Keynote *updated*
- Launchpad
- Leap Motion
- Mail
- Maps
- Messages
- Notes
- Numbers
- Pages
- PhotoBooth
- Preview *updated*
- QuickTime (x2)
- Reminders
- Safari
- Settings (now x2) *updated*
- Terminal *updated*
- Text Edit *updated*

Cocoa Design Patterns


Cocoa Design Patterns is superb! It is highly readable, thoroughly enjoyable, and filled to the brim with wisdom that will make you a more efficient and effective programmer. The authors utilize a consistent and self-contained approach to each chapter, making it easy to return to use as a reference. However, the material is so interesting and vital to Cocoa programmers that you’ll want to read it from cover to cover.

Советы и Рекомендации: Протоколы

Бывает такая штука в протоколах как необязательные / опциональные методы @optional. При работе с объектами/классами, особенно в больших проектах, заведомо не знаешь реализован тот или иной необязательный метод в классе, например, другим разработчиком класса. При компиляции проекта, компилятор не укажет на это даже в варнингах (warnings). После запуска приложения и обработке входящих объектов, в которых из них не будет реализации опциональных методов, естественно приложение упадет. Для проверки реализации опционального метода в классе/объекте рекомендуется использовать селекторы, т.е. вся отвественность ложиться на разработчика:

[objectName respondToSelector:@selector(protocolMethodName)]

т.е. здесь мы проверяем реализован ли в объекте/классе objectName метод описанный в протоколе protocolMethodName. Результат булевый YES | NO.

Как узнать, использует ли объект/класс протокол (подключен ли протокол)?:

[objectName conformsToProtocol:@protocol(protocolName)]

Результат булевый YES | NO.

25 мая 2014 г.

NSCollectionView без байндингов: Ячейки из NSView

В предыдущей статье я описал как создать NSCollectionView программно. В этой короткой статье я опишу как создать ячейки / итемы на основе кастомной NSView. Все почти также само как и с View-based NSTableView. Добавляем новый класс NSViewController, подключаем его в BVView.h:



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

@interface BVView : NSView {
    
    ViewController *customView;

}

@end

#import "BVView.h"

@implementation BVView

- (id)initWithFrame:(NSRect)frameRect
{
    // Создаем модель-вьюху
    customView = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];    
    
    self = [super initWithFrame:(NSRect)customView.view.frame];
    
    if (self) {
        
        [self addSubview:[customView view]];
        
    }
    
    return self;
}


В принципе все. Обращаться к элементам интерфейса можно через протокол/делегат (пример NSTableView).

24 мая 2014 г.

6 мая 2014 г.

3 мая 2014 г.

NSMutableString - пример

Класс NSString используется для хранения строк, но в нем присутствует небольшой недостаток. Мы не можем изменять строку которая хранится в экземпляре этого класса. С этой проблемой очень хорошо справляется класс NSMutableString. У него намного больше возможностей обработки строк в отличии от NSString.

Рассмотрим небольшой пример:
Создадим экземпляр класса NSMutableString.

NSMutableString *stringOne = [NSMutableString initWithCapacity: 15];
NSMutableString *stringTwo = [[NSMutableString alloc] initWithCapacity: 30];

В первом и втором примере мы создаем экземпляр класса с выделением под строку определенное количество символов (15 и 30). Второй пример характерен тем, что, мы сами контролируем процесс выделения и очистки памяти. Что произойдет если мы к выделенному количеству символов добавим еще некое количество и случайно выйдем за пределы выделенного количества символов? Ничего не произойдет. Приложение будет и дальше работать также само. Этот параметр носит характер оптимизации для компилятора по выделении памяти и значение этого параметра никак не влияет на длину строки.

По-практикуем:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        NSMutableString *mtStr = [[NSMutableString alloc] initWithCapacity:15];
        [mtStr appendString:@"— Будете у нас, на Колыме – милости просим!"];
        NSLog(@"%@", mtStr);
        
        [mtStr appendFormat:@" — Нет,%@", @" уж лучше вы к нам!"];
        NSLog(@"%@", mtStr);
        
        NSRange strRng = [mtStr rangeOfString:@" — Нет,"];
        [mtStr deleteCharactersInRange:strRng];
        NSLog(@"%@", mtStr);
        
        //[mtStr insertString:@" - Да" atIndex:43];
        //NSLog(@"%@", mtStr);
        
        [mtStr insertString:@" - Да" atIndex:strRng.location];
        NSLog(@"%@", mtStr);
        
        [mtStr setString:@"Новая строка"];
        NSLog(@"%@", mtStr);
    }
    return 0;
}

Результат выполнения:


29 апр. 2014 г.

Категории - теория и пример

Язык Objective-C обладает возможностью добавлять новые методы к уже существующим классам (т.е. расширение функциональности класса). При этом не требуется исходников класса и добавленные методы автоматически становятся доступными всем классам, унаследованным от изменяемого. Так можно добавить новый метод классу NSString (возьмем за пример) и этот метод автоматически добавится во все остальные классы.

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

Категория имеет свое имя, список методов и имя класса, который она расширяет. Описание категории имеет следующий вид:

#import "ClassName.h"
@interface ClassName (CategoryName)
  // объявление методов
@end

Реализация категории выглядит следующим образом:

#import "CategoryName.h"
@implementation ClassName (CategoryName)
  // реализация методов
@end

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

Пример.
Расширим класс NSString, добавим метод который будет проверять является ли файл аудио-файлом. Создадим проект Foundation и добавим в проект новый класс-категорию NSStringAudioExtension (наследуемый от NSString):


Объявим в NSStringAudioExtension.h метод - (BOOL) isAudioFile:

#import <Foundation/Foundation.h>

@interface NSString (NSStringAudioExtension)

- (BOOL) isAudioFile;

@end

В NSStringAudioExtension.m реализуем метод:

#import "NSString+NSStringAudioExtension.h"

@implementation NSString (NSStringAudioExtension)

- (BOOL) isAudioFile {
    
    if ([self hasSuffix:@".mp3"] || [self hasSuffix:@".wav"] || [self hasSuffix:@".arm"]) {

        return YES;

    }
    
    return NO;
}

@end

Дальше возвращаемся в main.m (технически класс NSString должен подхватить его расширение):

#import <Foundation/Foundation.h>
#import "NSString+NSStringAudioExtension.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        NSString *audioFileStr = @"Scooter feat. Vicky Leandros - C'est Bleu.mp3";
        
        if ([audioFileStr isAudioFile]) {
            
            NSLog(@"Да, это аудио-файл");
            
        } else {
            
            NSLog(@"Нет, это не аудио-файл");
            
        }
        
    }
    return 0;
}

Результат выполнения приложения:


Заменим .mp3 на .mp4, результат выполнения:


27 апр. 2014 г.

View-based NSTableView на основе ячеек из NSView (Злосчастная кнопка). Продолжение

В предыдущей статье о View-based NSTableView на основе ячеек из NSView не было реализации по использованию кнопки на виде (замечание в комментарии читателя). Порывшись в поиске (вместе с несуразными лексическими словосочетаниями), хоть какого-то решения так и не было найдено. Было решено использовать делегат и дать право AppDelegate кликать на эту злосчастную кнопку. 
Все бы ничего, но как узнать индекс этой чертовой вьюхи, на которой находится эта кнопка? Подумав, поломав голову вместе с мозгами, решил по нажатию кнопки AppDelegate-м передавать ему эту вьюху. Ведь все они разные, т.к. под каждую строку выделена память, естественно и адреса их будут разные.
Создаем делегат - добавляем в проект новый protocol-файл. Объявим в нем метод который будет передавать право тыканья этой кнопки AppDelegate-у.

#import <Foundation/Foundation.h>

@protocol ButtonControllerProtocol <NSObject>

@required
- (void) viewButtonClicked: (NSButton *) clickedButton view: (NSView *) viewCell;

@end

Далее в ViewController.h добавим экшен на кнопку, подключим AppDelegate и укажем какой метод использовать при нажатии этой кнопки.

- (IBAction)buttonInfo:(id)sender {
    
    AppDelegate *myAppDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
    [myAppDelegate viewButtonClicked:sender view:[self view]];
    
}

В AppDelegate.h подключим созданный протокол и пропишем делегат:

#import "ButtonControllerProtocol.h"

@interface AppDelegate : NSObject <NSApplicationDelegate, NSTableViewDelegate, NSTableViewDataSource, ButtonControllerProtocol> {

Реализуем протокольный метод:

- (void)viewButtonClicked: (NSButton *) clickedButton view: (NSView *) viewCell {
    NSLog (@"click");
}

Все бы хорошо, метод обрабатывается, выдает определенный результат, а дальше-то что? А дальше нам якобы нужно как-то менять данные на вьюхе. Вот здесь-то и пришлось помучатся. Хотя все оказалось немного проще. Мы помним что окно как главный вид, состоит из подвидов разной сложности, т.е. проще говоря на нашей вьюхе-подвиде тоже есть подвиды (subviews) - nsimageview, nstextfield и т.д. Остается лишь получить к ним доступ. Получим подвиды на вьхе-строке:


Загоним эти объекты в массив и потом создадим указатели на эти объекты и будем обращаться к непосредственно новым объектам-подвидам:

- (void)viewButtonClicked: (NSButton *) clickedButton view: (NSView *) viewCell {

    // Получаем строку-вид в нашей таблице
    NSView *clickedView = [clickedButton superview];
    
    // Получаем список подвидов в строке-виде
    NSArray *viewObjectsArray = [NSArray arrayWithArray:[clickedView subviews]];
    
    // Коннектимся к подвиду и задаем значение
    NSImageView *viewObjectImage = [viewObjectsArray objectAtIndex:0];
    [viewObjectImage setImage:[NSImage imageNamed:@"Slice 1"]];
    
    NSTextField *viewObjectFirstTextField = [viewObjectsArray objectAtIndex:1];
    [viewObjectFirstTextField setStringValue:@"Slice 1"];
    
}

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

31 мар. 2014 г.

Компонент интерфейса в заголовке окна

В обычной программе за отрисовку окна отвечает недокументированный класс NSThemeFrame.
Создаем окно с оутлетом window на это окно. Добавляем NSView и тоже создаем на него привязку оутлет:
Добавляем на вьюху компонент NSPopupButton, убираем флажок Bordered в Инспекторе Атрибутов. В AppDelegate.h должен быть такой код:

#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate> {
    
    IBOutlet NSWindow *window;
    IBOutlet NSView *itemView;
}

- (void)composeInterface;

@end


AppDelegate.m:

#import "AppDelegate.h"

@implementation AppDelegate

- (void)awakeFromNib
{
[self composeInterface];
}

- (void)composeInterface
{
// Получаем указатель на фрейм окна
NSView *themeFrame = [[window contentView] superview];
NSRect contentWindowFrame = [themeFrame frame]; // размер фрейма окна
NSRect itemViewFrame = [itemView frame]; // размер фрейма вьюхи
NSRect newFrame = NSMakeRect(
                                 contentWindowFrame.size.width - itemViewFrame.size.width, // x позиция
                                 contentWindowFrame.size.height - itemViewFrame.size.height, // y позиция
                                 itemViewFrame.size.width, // ширинв
                                 itemViewFrame.size.height); // высота
    
[itemView setFrame:newFrame];
[themeFrame addSubview:itemView];
}

@end


Вместо NSPopupButton можна добавить любой элемент на вьюху. Главное чтобы высота компонента не была больше чем сам Title Bar.
Дальше все просто. Делаем оутлет на PopupButton, и делаем с ним все что душе угодно.

27 мар. 2014 г.