понедельник, 18 ноября 2013 г.

iOS How to load another storyboard. Как загрузить другую Storyboard

Для экранов 3'5 и 4 дюйма можно использовать различные Storyboard так как это дает возможность удобно проектировать интерфейс под разные размеры экранов. Для этого необходимо создать еще одну Storyboard разработать в ней соответствующей интерфейс. В файла AppDelegate.m необходимо добавить соответствующий код в метод didFinishLaunchingWithOptions для загрузки необходимой нам Storyboard. В этом методе необходимо при запуске приложения на устройстве определить, какое устройство сейчас используется 3'5 или 4 дюйма (определяется это в зависимости от высоты экрана для 3'5 дюймового это 480 точек, а для 4 дюймового это 568 точек). Далее создаем UIStoryboard на основании соответствующего файла и создаем первый ViewController. После этого создаем окно и назначаем этому окну initial View Controller.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
 
    CGSize iOSDeviceScreenSize = [[UIScreen mainScreen] bounds].size;
    UIViewController *initialViewController = nil;
    if (iOSDeviceScreenSize.height == 480) {
 
        UIStoryboard *iPhone35Storyboard = [UIStoryboard storyboardWithName:@"Storyboard-iphone35" bundle:nil];
 
        initialViewController = [iPhone35Storyboard instantiateInitialViewController];
 
    } else if (iOSDeviceScreenSize.height == 568) {
 
        UIStoryboard *iPhone4Storyboard = [UIStoryboard storyboardWithName:@"Main_iPhone" bundle:nil];
 
        initialViewController = [iPhone4Storyboard instantiateInitialViewController];
 
    }
 
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
 
    self.window.rootViewController = initialViewController;
 
    [self.window makeKeyAndVisible];
 
    return YES;
}

суббота, 26 октября 2013 г.

How to hide status bar in iOS 7

Изначально в приложении для iOS 7 status bar показывается по умолчанию. 

Приложение со status bar

Для того чтобы скрыть status bar в приложении для iOS 7 необходимо сделать следующее.

1. Выбрать проект в навигаторе, перейти в Targets и выбрать проект там, перейти на вкладку Info. На вкладке Info в разделе Custom iOS Target Properties нажать правую кнопку и выбрать Add Row. Нужно добавить строку Status bar is initially hidden и установить её значение YES 



Добавляем строку Status bar is initially hidden в настройки проекта   

2. Точно также добавить строку View controller-based status bar appearance и установить ей значение NO
Добавляем строку View controller-based status bar appearance в настройки проекта

3. Переходим на вкладку General и тут находим строку Status Bar Style и ставим галочку напротив Hide during application launch

Теперь запустим приложение - вот так оно будет выглядеть без status bar



воскресенье, 20 октября 2013 г.

iOS Книги необходимые для разработчика

Для того, чтобы стать настоящим профессионалом в разработке приложения для iOS необходимо много читать. Разработка под  iOS требует знания языка Objective-C и поэтому часть книг, которые я тут перечислю рассказывают о том как программировать на этом языке. Остальные книги рассматривают вопрос программирования под iOS непосредственно. Во всех книгах перечисленных здесь я нашел много полезного и интересного для себя. Еще до того, как я прочитал некоторые из них я уже писал приложения для iOS, но когда читаешь книгу все раскладывается по полочкам, начинаешь понимать как все устроено и как работают приложения. Из книг можно взять для себя много полезных решений.

1. Learn C on the Mac For OS X and iOS 2nd Edition (By David Mark , James Bucanek)



2. Learn Objective-C on the Mac For OS X and iOS 2nd Edition (By Scott Knaster , Waqar Malik , Mark Dalrymple)

четверг, 17 октября 2013 г.

iOS How to define interface orientation


Бывает необходимо определить текущее положение экрана - горизонтальное или вертикальное.

UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
 
if (interfaceOrientation == UIInterfaceOrientationMaskPortrait || 
    interfaceOrientation == UIInterfaceOrientationMaskPortraitUpsideDown) {
 
      NSLog(@"%@", @"portrait orientation"); // вертикальное
 
} else {
 
      NSLog(@"%@", @"landscape orientation");  // горизонтальное
 
}

среда, 16 октября 2013 г.

iOS How to define device type


Как определить тип устройства на котором запускается приложение. Чаще всего это необходимо для того чтобы задать размеры каких-то компонентов.

UIUserInterfaceIdiom idiom = UI_USER_INTERFACE_IDIOM();
if (idiom == UIUserInterfaceIdiomPad) {
  NSLog(@"%@", @"iPad");
} else {
   NSLog(@"%@", @"iPhone");
}


понедельник, 19 августа 2013 г.

IOS how to trim string

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

NSString *str= [textField text];
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
NSString *trimmedStr = [str stringByTrimmingCharactersInSet:whitespace];

Reset UITextField's original placeholder text

Для того чтобы обрабатывать события связанные с вводом сиволов в текстовое поле, необходимо чтобы ваш ViewController был делегатом  UITextFieldDelegate

@interface ViewController : UIViewController<UITextFieldDelegate> 

Для обработки появление и исчезновения placeholder'а необходимо реализовать два метода из UITextFieldDelegate

- (void)textFieldDidBeginEditing:(UITextField *)textField {
    textField.placeholder = nil;
}
 
- (void)textFieldDidEndEditing:(UITextField *)textField {
    textField.placeholder = @"Your Placeholdertext";
}

воскресенье, 18 августа 2013 г.

Method overloading in Objective-C

Objective-C не поддерживает перегрузку методов, так что необходимо использовать различные имена при создании методов. Однако заметим, что имя метода включает в себя сигнатуру ключевых слов (имена параметров, которые идут до ":"), так что два следующих метода будут разными, несмотря на то, что они оба начинаются с "writeToFile"

-(void) writeToFile:(NSString *)path fromInt:(int)anInt;
-(void) writeToFile:(NSString *)path fromString:(NSString *)aString;

Имена двух методов: "writeToFile:fromInt:" и "writeToFile:fromString:"

Categories. UIColor from Hex and from RGB

Цвет может задаваться через шестнадцатиричную запись или через RGB. Для того, чтобы создать нужный нам цвет, зная только его шестнадцатиричное значение, необходимо создать так называемую категорию. Категория позволяет добавить к существующим классам новые методы. То есть мы добавим к классу UIColor методы которые позволят создавать цвет, используя шестнадцатиричную запись или RGB значение цвета.

UIColor+Hex.h

#import <UIKit/UIKit.h>
 
@interface UIColor (Hex)
 
+ (UIColor *) colorWithHexString:(NSString *)aHexString;
 
+ (UIColor *) colorWithRGBHex:(UInt32)aHex;
 
@end


UIColor+Hex.m

#import "UIColor+Hex.h"
 
@implementation UIColor (Hex)
 
+ (UIColor *) colorWithHexString:(NSString *)aHexString
{
    NSScanner *scanner = [NSScanner scannerWithString:aHexString];
    unsigned hexNum;
 
    if (![scanner scanHexInt:&hexNum])
    {
        return nil;
    }
 
    return [UIColor colorWithRGBHex:hexNum];
}
 
+ (UIColor *) colorWithRGBHex:(UInt32)aHex
{
    int r = (aHex >> 16) & 0xFF;
    int g = (aHex >> 8) & 0xFF;
    int b = (aHex) & 0xFF;
 
    return [UIColor colorWithRed:r / 255.0f
                           green:g / 255.0f
                            blue:b / 255.0f
                           alpha:1.0f];
}
 
@end

Использование метода категории UIColor+Hex

UIColor *color = [UIColor colorWithHexString:@"c90606"];

UITextView with placeholder

Стандартный компонент UITextView не имеет placeholder, поэтому следует разработать подкласс этого компонента, который бы имел placeholder.

UIPlaceHolderTextView.h

#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>
 
 
@interface UIPlaceHolderTextView : UITextView {
    NSString *placeholder;
    UIColor *placeholderColor;
 
@private
    UILabel *placeHolderLabel;
}
 
@property (nonatomic, retain) UILabel *placeHolderLabel;
@property (nonatomic, retain) NSString *placeholder;
@property (nonatomic, retain) UIColor *placeholderColor;
 
-(void)textChanged:(NSNotification*)notification;
 
@end

UIPlaceHolderTextView.m

#import "UIPlaceHolderTextView.h"
 
 
@implementation UIPlaceHolderTextView
 
@synthesize placeHolderLabel;
@synthesize placeholder;
@synthesize placeholderColor;
 
- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
#if __has_feature(objc_arc)
#else
    [placeHolderLabel release]; placeHolderLabel = nil;
    [placeholderColor release]; placeholderColor = nil;
    [placeholder release]; placeholder = nil;
    [super dealloc];
#endif
 
}
 
- (void)awakeFromNib
{
    [super awakeFromNib];
    [self setPlaceholder:@""];
    [self setPlaceholderColor:[UIColor lightGrayColor]];
    [[NSNotificationCenter defaultCenter] addObserver:self 
      selector:@selector(textChanged:) 
      name:UITextViewTextDidChangeNotification object:nil];
}
 
- (id)initWithFrame:(CGRect)frame
{
    if( (self = [super initWithFrame:frame]) )
    {
        [self setPlaceholder:@""];
        [self setPlaceholderColor:[UIColor lightGrayColor]];
        [[NSNotificationCenter defaultCenter] addObserver:self 
          selector:@selector(textChanged:) 
          name:UITextViewTextDidChangeNotification object:nil];
    }
    return self;
}
 
- (void)textChanged:(NSNotification *)notification
{
    if([[self placeholder] length] == 0)
    {
        return;
    }
 
    if([[self text] length] == 0)
    {
        [[self viewWithTag:999] setAlpha:1];
    }
    else
    {
        [[self viewWithTag:999] setAlpha:0];
    }
}
 
- (void)setText:(NSString *)text {
    [super setText:text];
    [self textChanged:nil];
}
 
- (void)drawRect:(CGRect)rect
{
    if( [[self placeholder] length] > 0 )
    {
        if ( placeHolderLabel == nil )
        {
            placeHolderLabel = [[UILabel alloc] 
              initWithFrame:CGRectMake(8,8,self.bounds.size.width - 16,0)];
            placeHolderLabel.lineBreakMode = NSLineBreakByWordWrapping;
            placeHolderLabel.numberOfLines = 0;
            placeHolderLabel.font = self.font;
            placeHolderLabel.backgroundColor = [UIColor clearColor];
            placeHolderLabel.textColor = self.placeholderColor;
            placeHolderLabel.alpha = 0;
            placeHolderLabel.tag = 999;
            [self addSubview:placeHolderLabel];
        }
 
        placeHolderLabel.text = self.placeholder;
        [placeHolderLabel sizeToFit];
        [self sendSubviewToBack:placeHolderLabel];
    }
 
    if( [[self text] length] == 0 && [[self placeholder] length] > 0 )
    {
        [[self viewWithTag:999] setAlpha:1];
    }
 
    [super drawRect:rect];
}
 
@end

UITableViewCell, show delete button on swipe

В таблице UITableView есть такая штука, когда проводишь пальцем по строке, то появляется кнопка удалить. Как сделать чтобы эта кнопка появлялась или не появлялась и как обрабатывать нажатие на кнопку удалить.

// Override to support conditional editing of the table view.
// This only needs to be implemented if you are going to be returning NO
// for some items. By default, all items are editable.
- (BOOL)tableView:(UITableView *)tableView 
  canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    // Return YES if you want the specified item to be editable.
    return YES;
}
 
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView 
  commitEditingStyle:(UITableViewCellEditingStyle)editingStyle 
  forRowAtIndexPath:(NSIndexPath *)indexPath {
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        //add code here for when you hit delete
    }    
}

четверг, 15 августа 2013 г.

Proper URL encoding


При передаче параметров в строке URL в iOS могут возникнуть проблемы с формированием правильной строки адреса  URL. Причиной этого могут быть не правильно закодированные символы в адресе, например пробелы. Чтобы этого избежать необходимо кодировать строку адреса. Закодировать строку которая будет использоваться в качестве URL в iOS очень просто. Для этого достаточно выполнить лишь один метод, который преобразует незакодированную строку в закодированную.

Непосредственно сам метода кодировки
NSString *fullUrlString = [loginUrlString stringByAppendingString:params];
 
NSString *properlyEscapedURL = 
  [fullLoginUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

Пример применения метода кодировки
NSString *urlString = @"/rest/resource/method";
 
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
 
[dateFormatter setDateFormat:@"dd.MM.yyyy"];
 
NSDateFormatter *dateFormatterForSecondDate = 
  [[[NSDateFormatter alloc] init] autorelease];
 
[dateFormatterForSecondDate setDateFormat:@"dd.MM.yyyy HH:mm"];
 
NSString *userIdStr = [currentUserIdNumber stringValue];
 
NSString *userIdParam = [@"?userId=" stringByAppendingString:userIdStr];
 
NSString *fromCityParam = [@"&fDispCity=" stringByAppendingString:fromCity];
 
NSString *toCityParam = [@"&fDeliveryCity=" stringByAppendingString:toCity];
 
NSString *fromDateParam = 
  [@"&fDate=" stringByAppendingString:[dateFormatter stringFromDate:fromDate]];
 
NSString *weightParam = [@"&fTruckCategory=" stringByAppendingString:
  [MyEnums getNameForTruckCategory:truckCategory]];
 
NSString *toDateParam = [@"&fDateAlong=" stringByAppendingString:
  [dateFormatterForSecondDate stringFromDate:toDate]];
 
NSMutableString *params = [NSMutableString stringWithString:userIdParam];
[params appendString:fromCityParam];
[params appendString:toCityParam];
[params appendString:fromDateParam];
[params appendString:weightParam];
[params appendString:toDateParam];
 
NSString *fullUrlString = [loginUrlString stringByAppendingString:params];
 
NSString *properlyEscapedURL = 
  [fullLoginUrlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
 
NSURL *url = [NSURL URLWithString:properlyEscapedURL];

String representation of NSDate

Для того чтобы получить строковое представление даты необходимо вызывать метод description класса NSDate

NSDate* currentDate = [NSDate date];
 
NSString* dateInString = [currentDate description];

NSDateFormatter example

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

NSDate *currentDateTime = [NSDate date];
 
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
 
[dateFormatter setDateFormat:@"dd.MM.yyyy HH:mm"];
 
NSString *dateInStringFormated = [dateFormatter stringFromDate:currentDateTime];
 
NSLog(@"%@", dateInStringFormated);
 
[dateFormatter release]; 

Set the time to date

Для манипуляций с датой необходимо использовать классы NSDateComponents и NSCalendar. Напрмер, ниже показано как задать сегодняшней дате определенное время - 23 часа 59 минут.

NSDate *now = [NSDate date];
NSCalendar *calendar = [[[NSCalendar alloc] 
  initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
NSDateComponents *components = [calendar components:
  NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit 
  fromDate:now];
[components setHour:23];
[components setMinute:59];
NSDate *today23h59m = [calendar dateFromComponents:components];

вторник, 13 августа 2013 г.

UIScrollView scroll to top programmatically

Программно перемотать область прокрутки наверх можно двумя способами

Первый
[self.scrollView setContentOffset:CGPointZero animated:YES];

Второй
[self.scrollView 
  setContentOffset:CGPointMake(self.scrollView.contentOffset.x, 0) 
  animated:YES];

понедельник, 12 августа 2013 г.

How to add a UIButton in the header of UITableView header

Для добавления кнопки в заголовок таблицы вам необходимо использовать методы делегаты класса UITableView

Метод, в котором указываем высоту View, которую мы будем вставлять в заголовок
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section

Метод, в котором определяем View и содержащуюся в ней кнопку
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section

Пример добавления кнопки в заголовок таблицы
-(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
 
    return 58;
 
}
 
 
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
 
    UIView *customView = [[[UIView alloc] 
      initWithFrame:CGRectMake(10.0, 0.0, self.view.bounds.size.width, 53.0)] 
      autorelease];
 
    CustomGradientButon *changeConditionsButton = 
      [[CustomGradientButon alloc] 
      initWithFrame:CGRectMake(
      (self.view.bounds.size.width - 250)/2, 15.0, 250.0, 38.0)];
 
    [changeConditionsButton setButtonTitleLabel:@"Изменить условия поиска"];
    [changeConditionsButton addTarget:self 
      action:@selector(changeConditionsButtonClicked) 
      forControlEvents:UIControlEventTouchUpInside];
 
    [customView addSubview:changeConditionsButton];
 
    return customView;
 
}
 
-(void) changeConditionsButtonClicked {
 
    if (!fromFilter) {
       [self performSegueWithIdentifier:@"ChangeConditions" sender:self]; 
    } else {
        [self.navigationController popViewControllerAnimated:YES];
    }
 
}

воскресенье, 11 августа 2013 г.

Passing Cyrillic characters as a URL parameter


NSString *str = textField.text; 
 
NSString *serverAddress = SERVER_ADDRESS;
 
NSString *restMethodAddress = @"/rest/someResource/someMethod";
 
NSString *encodeString = 
[str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
 
NSString *param = [NSString stringWithFormat:@"?charSequence=%@", encodeString];
 
NSMutableString *fullRequestAddress = [NSMutableString stringWithString:serverAddress];
[fullRequestAddress appendString:restMethodAddress];
[fullRequestAddress appendString:likeCitiesParam];
 
NSURL *url =[NSURL URLWithString:fullRequestAddress];
 
NSMutableURLRequest *theRequest = [NSMutableURLRequest 
requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60];
 
[theRequest setHTTPMethod:@"GET"];
 
NSURLConnection connection = 
[[NSURLConnection alloc] initWithRequest:theRequest delegate:self ];

воскресенье, 30 июня 2013 г.

Singleton на Objective-C

Реализация шаблона проетирования "Одиночка" на Objective-C выглядит следующим образом.


AuthManager.h

#import <Foundation/Foundation.h>
 
@interface AuthManager : NSObject
 
@property (nonatomic, assign) long long currentUserId;
 
@property (nonatomic, copy) NSString *springSecurityToken;
 
+(AuthManager *) sharedInstance;
 
@end


AuthManager.m

#import "AuthManager.h"
 
@implementation AuthManager
 
@synthesize currentUserId;
 
@synthesize springSecurityToken;
 
+(AuthManager *)sharedInstance {
 
    static dispatch_once_t once;
 
    static AuthManager *sharedInstance = nil;
 
    dispatch_once(&once, ^{ sharedInstance = [[self alloc] init]; });
 
    return sharedInstance;
 
}
 
@end

четверг, 6 июня 2013 г.

Как задать title для кнопки delete в UITableView

В таблице TableView  по умолчанию есть кнопка delete, которая появляется когда пользователь  проводит пальцем по ячейке (строке) имеет title "delete". Как задать этой кнопке другой нужный нам текст например "Удалить" ;) Для этого неоюходимо реализовать метод titleForDeleteConfirmationButtonForRowAtIndexPath который определен в UTableViewDelegate 

среда, 5 июня 2013 г.

Получение и отправка на сервер координат iOS устройства

Одной из задач в разработке приложения для iPhone стала задача получить географические координаты iOS устройства (широту и долготу) и отправлить их на сервер. Реализуется данная задача с помощью использования классов из CoreLocation framework.  Для этого необходимо добавить CoreLocation framework к проекту.

суббота, 9 марта 2013 г.

Xcode 4.2 for Snow Leopard

Для Mac OS X 10.6 (Snow Leopard) последней актуальной версией среды разработки xcode, которую можно бесплатно скачать с сайта apple является xcode версии 3.2.6. Чтобы скачать версию 4.2 нужно владеть платным аккаунтом. Причем, доступна для бесплатного скачивания версия xcode 4.2 для Mac OS X 10.7, но она не будет устанавливаться на Snow Leopard. Однако на просторах интернета можно найти торренты с версией xcode 4.2 именно для Snow Leopard.

Важное замечание - при установке лучше выставить дату 1 января 2012 года, иначе xcode может не установиться вообще или установиться криво (не будет потом запускаться).

Как удалить xcode полностью

Начал разрабатывать своё первое приложение для iOS на старом маке. Там уже была установлена среда разработки xcode версии 3.2.6. Решил установить xcode посвежее. Но предварительно нужно полностью удалить устновленную старую версию. Можно просто удалить папку, в которую установлен xcode - это папка /Developer. Для того, чтобы полностью удалить xcode необходимо запустить терминал и набрать там команду
sudo /Developer/Library/uninstall-devtools --mode=all
Внимание! перед словом mode два раза символ "-"
После чего ввести пароль своей учетной записи. После этого xcode начнет удаляться. Удаление может длится достаточно долго от 5 до 15 минут. После этого сможно устанавливать новый xcode.