среда, 8 января 2014 г.

Эффект листания изображения для Iphone, IOS 5+

В этой статье я расскажу как сделать эффект листания изображений как страниц в книге или в отрывном календаре. Очень часто приходится сталкиваться с задачами реализовать мини галерею или список изображений. Что бы сделать интерфейс красивым и понятным для пользователя есть множество путей. Сегодня я покажу как быстро и просто сделать листание изображений, что бы они переворачивались как листы при помощи протягивания пальцем по экрану, Этот принцип конечно же построен на работе с GestureRecognizer.

Для начала создайте проект в Xcode выбрав Single View Application. (Я работаю в Xcode 4.6 поэтому буду показывать на примере с использованием Storyboard)
Название не имеет значения. Ставим галочку Use Storyboards и сохраняем проект где нибудь себе в папку. Так у нас создастся наш коренвой ViewController  с именем которое вы указали в качестве названия приложения и наш  Storyboard.


Давайте сразу приступим к созданию UIimageView который будет перелистыватся. Перейдите на ваш Storyboard он пока пустой и добавим мы в него пока всего одну картинку при помощи  элемента  UIimageView Найдите его в списке объектов и разместите на вашей Storyboard.

Теперь в h файле вашего контроллера необходимо создать IBOutlet для связи с нашим UIImageView
Вот как это выглядит у меня:
@interface testViewController : UIViewController{
IBOutlet UIImageView *myimage;
}
Теперь можно назначить New Referensing Outlet Collections нашему myimage.

 Затем выбираем New Referensing Outlet Collections нажимая левой кнопкой мышки на кружочке и тянем к левому блоку в наш UIView. И связываем с myimage.

Теперь UIImageView можно назначить картинку и сделать это можно через опять таки Storyboard, как это показано на рисунке.
Также очень важно не забыть поставить галочку Use Interaction Enabled

Далее переходим к m файлу нашего контроллера и находим в нем метод – (void)viewDidLoad
Добавим туда  код который по сути привяжет использования жеста Swipeк нашей картинке и заставит её переворачиваться в зависимости от горизонтальных движений пальцами по экрану телефона.
 [myimage setUserInteractionEnabled:YES];
//перетащили пальцем вправо
UISwipeGestureRecognizer *swipenext = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(getNext)];
[swipenext setDirection:UISwipeGestureRecognizerDirectionUp | UISwipeGestureRecognizerDirectionLeft];
[myimage addGestureRecognizer:swipenext];
//перетащили пальцем влево
UISwipeGestureRecognizer *swipeback = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(getPrev)];
[swipeback setDirection:UISwipeGestureRecognizerDirectionDown | UISwipeGestureRecognizerDirectionRight];
[myimage addGestureRecognizer:swipeback];
Теперь подробней поговорим о коде.
UISwipeGestureRecognizer *swipenext = [[UISwipeGestureRecognizer alloc]
initWithTarget:self
action:@selector(null)]; – создаёт объект жеста swipenext с параметрами
Обратите внимание на параметр action:@selector(getNext) – сдесь мы можем указать метод который выполнится после перелистывания например это может быть показать следующую картинку getNext.  Посмотрим реализацию этого метода
-(void) getNext{
//устанавливаем анимацию переворачивания
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1]; // сколько длится анимация – в секундах
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:myimage cache:YES]; //овернуть «листок» вверх
[UIView commitAnimations];
}
// почти тоже самое в метотоде getPrev
-(void) getPrev{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:myimage cache:YES]; //отвернуть листок вниз
[UIView commitAnimations];
}
Теперь запустим проект и потягаем мышкой по экрану эмулятора (или телефона если вы работаете с реальным девайсом). вы должны увидеть перелистывание подобное этому:

Конечно в качестве направления переворачивания листа в параметр setAnimationTransition  можноустанавливать значения UIViewAnimationTransitionFlipFromLeft и UIViewAnimationTransitionFlipFromRight но это уже будет просто поворот рисунка, а не перелистывание.
Пока конечно же рисунок остаётся тем же, что и был но мы можем вставить метод который менял бы что то например между строк
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:myimage cache:YES];
//добавить сюда выполнение метода
[UIView commitAnimations];
Тогда сможем реализовать подмену рисунка плавно, а пока на этом всё спасибо. что прочиталю статью.

Работа с фото видео камерой в IOS IPhone используя UIImagePickerController

У многих разработчиков мобильных приложений возникает вопрос о реализации работы с камерой. Я уже описывал этот процесс для Android теперь хочу сделать краткое описание для IOS на IPhone. Речь пойдёт именно об использовании UIImagePickerController как самого простого способа. Описывать подробно создание проекта и установки кнопки в storyboard я не буду это вы можете посмотреть в моей прошлой статье.

Предпочитается, что у вас уже есть кнопка по которой мы хотим вызвать камеру и получить например фото после того как вы нажмете фотографировать. Поэтому я опишу лишь методы которые необходимо реализовать в класе вашего ViewCotroller-а.
Итак вызов камеры:
-(IBAction) makePhoto:(id)sender{
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]){
// Создание image picker controller
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
// Устанавливаем сорс для камеры
imagePicker.sourceType =  UIImagePickerControllerSourceTypeCamera;
imagePicker.videoQuality = UIImagePickerControllerQualityTypeHigh;
// Текущий Delegate
imagePicker.delegate = self;
imagePicker.mediaTypes = [UIImagePickerController  availableMediaTypesForSourceType:imagePicker.sourceType];
// Показываем image picker
[self presentModalViewController:imagePicker animated:YES];
}else{
NSLog(@»Ваше устройство не поддерживает эту функцию»);
}
}
В этом методе мы настраиваем UIImagePickerController и показываем пользователю активность в которой он работает, и соответственно можно сделать фото. Поскольку делегатом является self,  то есть реализация методов обработки полученных результатов должна быть в этом же классе.
Подвяжите метод типа IBAction к кнопке на Tuch up inside и запустите проект. Конечноже проверять необходимо на реальном устройстве, так как на эмуляторе камеры нет и в системный лог вы получите сообщение «Ваше устройство не поддерживает эту функцию». так как в строке
if ([UIImagePickerController isSourceTypeAvailable: UIImagePickerControllerSourceTypeCamera]){
мы проверяем наличие камеры на устройстве. Итак если вы запустите проект на реальном устроействе и нажмете на свою кнопку то увидите, что запустилась активность камеры, теперь можно сделать фото. Но после нажатия кнопки Use ничего не произойдет так как нам нужно реализовать ещё метод - (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info поскльку делегатом для UIImagePickerController является данный класс в котором он вызван,
Итак код метода:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//определить медиа тип файла
NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ( [ mediaType isEqualToString:@"public.image" ]) { //если файл – изображение
// Берем изображение из информации словаря
UIImage *image = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
//получить путь к файлу
NSURL* imagePath = (NSURL *)[info valueForKey:UIImagePickerControllerReferenceURL];
NSString* chosed_imagePath = [imagePath path];
//формируем file-data изображения
NSData* imageData = UIImageJPEGRepresentation(image, 1.0);
}else if ( [ mediaType isEqualToString:@"public.movie" ]){ // пользователь снял видео
NSString *moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
}
}
Теперь подробнее. Как видно из данного примера мы можем получить 2 типа контента с камеры: фото и видео. У данных о фотографии мы можем получить путь, url и NSData то есть само байтовое представление файла, и  что немало важно NSData хранится в памяти и если вам не нужны эти данные лучше не хнатить их в ОЗУ а пользоваться файлом на мобильном устройстве . Поэтому как дальше работать с этими данными вам решать) У видео файла также можно получить путь и NSData но в отличии от фото оно уже в медиа-галерее вашего устройства. И так опишу ещъ один метод для сохранения изображения в медиа галерею для дальнейшей работы с ним.
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
Как вы видите в качетсве входного параметра в этом методе используется image объект типа UIImage полученный нами из камеры. Еесли вам это нужно используйте это вот так:
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
//определить медиа тип файла
NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ( [ mediaType isEqualToString:@"public.image" ]) { //если файл – изображение
// Берем изображение из информации словаря
UIImage *image = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
UIImageWriteToSavedPhotosAlbum(image, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}else if ( [ mediaType isEqualToString:@"public.movie" ]){ // пользователь снял видео
NSString *moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
}
}
Конечно возможно вам понадобится обработчик didFinishSavingWithError – это метод который выполнится после сохранения рисунка и может содержать ошибку, о которой нужно сообщить пользователю
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error
contextInfo:(void *)contextInfo
{
// проверка на ошибки
if (error != NULL) {
// показать ошибку…
UIAlertView* minhaCritica = [UIAlertView new];
minhaCritica.title = @»Ошибка»;
[minhaCritica addButtonWithTitle:@"Ок"];
minhaCritica.message = @»Фото не сохранилось»;
minhaCritica.delegate = self;
[minhaCritica show];
[minhaCritica release];
//это обычный алерт с кнопкной ОК и сообщением
} else  // ошибок нет
{
// показать сообщение о том что картинка сохранена
UIAlertView* minhaCritica = [UIAlertView new];
minhaCritica.title = @»Успешно»;
[minhaCritica addButtonWithTitle:@"Ок"];
minhaCritica.message = @»Фото  сохранилось»;
minhaCritica.delegate = self;
[minhaCritica show];
[minhaCritica release];
}
}
Как мы видим в обработчике идет проверка на ошибку и два варианта или успешно или неудачно тогда покажем alert с тем или иным тектом. Теперь можно запустить проект и проверить как работает получение фото с камеры и сохраненеи в галерею.

Правильный разоворот изображения в IOS

Не так давно натолкнулся на проблему правильно повернуть картинку на нужный угол. Чаще всего это 90,180 градусов. Причем проблема заключалась не только в том, что бы развернуть картинку для пользователя на экране IPhone, а и сохранить изменения в графическом контексте, что бы запомнить эту трансформацию. Перебрав кучу методов я остановился на более простом и менее нагрузочном для системе методе. Данный способ не обрежет картинку не по сторонам ни по высоте или ширине, что немаловажно.

И так приступим. Подразумевается что у вас уже есть проект с размещенным на ViewVontroller-е вашей UIImageView куда вы будете показывать картинку до и полсе разворота. Поэтому я опишу лишь методы по работе с самим изображением.
Итак в методе viewDidLoad я подгружаю картинку из проекта
UIImage *img = [UIImage imageNamed:@"test.png"];
mainimage.image = img;
где mainimage это ваш UIImageView
Теперь релазуем два метода для переворота картинки вправо и влево:
-(void) RotateToLeft{
mainimage.image = [self imageByRotatingImage:img fromImageOrientation:UIImageOrientationLeft];
}
-(void)RotateToRight{
mainimage.image = [self imageByRotatingImage:img fromImageOrientation:UIImageOrientationRight];
}
Конечно вы можете написать эти методы как -(IBAction) и привязать вызов к кнопкам, но это не слишком сложно, что бы тратить на это время в этой статье :)
Итак мы видим, что в обоих случаях вызывается один и тот же метод -(UIImage*)imageByRotatingImage:(UIImage*)initImage fromImageOrientation:(UIImageOrientation)orientation только с разным параметром вконце. Он то как раз и указывает на ориентацию изображения в которую необходимо повернуть  картинку. Взял я его гдето на просторах интернетов и немножко окрасивил для понятного использования. Перед просмотром листинга кода метода хочу сказать, что перед его вызовом подразумевается, что текущая картинка имеет ориентацию UIImageOrientationUp.
Итак сам метод:
-(UIImage*)imageByRotatingImage:(UIImage*)initImage fromImageOrientation:(UIImageOrientation)orientation
{
CGImageRef imgRef = initImage.CGImage;
CGFloat width = CGImageGetWidth(imgRef);
CGFloat height = CGImageGetHeight(imgRef);
CGAffineTransform transform = CGAffineTransformIdentity;
CGRect bounds = CGRectMake(0, 0, width, height);
CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef));
CGFloat boundHeight;
UIImageOrientation orient = orientation;
switch(orient) {
case UIImageOrientationUp: //EXIF = 1
return initImage; //если прислать в качестве параметра orientation – UIImageOrientationUp метод вернёт саму картинку целой и невредмой
break;
case UIImageOrientationUpMirrored: //EXIF = 2  – Зеркальное отображение
transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0);
transform = CGAffineTransformScale(transform, -1.0, 1.0);
break;
case UIImageOrientationDown: //EXIF = 3 – перевернет вертикально
transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
case UIImageOrientationDownMirrored: //EXIF = 4 – Вертикальное зеркальное отображение
transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
break;
case UIImageOrientationLeftMirrored: //EXIF = 5
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width);
transform = CGAffineTransformScale(transform, -1.0, 1.0);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
break;
case UIImageOrientationLeft: //EXIF = 6 – Перевернуть влево -90 градусов
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(0.0, imageSize.width);
transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0);
break;
case UIImageOrientationRightMirrored: //EXIF = 7
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeScale(-1.0, 1.0);
transform = CGAffineTransformRotate(transform, M_PI / 2.0);
break;
case UIImageOrientationRight: //EXIF = 8 – Вправо тоесть +90 градусов по часовой стрелке
boundHeight = bounds.size.height;
bounds.size.height = bounds.size.width;
bounds.size.width = boundHeight;
transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0);
transform = CGAffineTransformRotate(transform, M_PI / 2.0);
break;
default:
[NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"];
}
// Вот тут создается графический контекст
CGContextRef    context = NULL;
void *          bitmapData;
int             bitmapByteCount;
int             bitmapBytesPerRow;
bitmapBytesPerRow   = (bounds.size.width * 4);
bitmapByteCount     = (bitmapBytesPerRow * bounds.size.height);
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL)
{
return nil;
}
CGColorSpaceRef colorspace = CGImageGetColorSpace(imgRef);
context = CGBitmapContextCreate (bitmapData,bounds.size.width,bounds.size.height,8,bitmapBytesPerRow,
colorspace,kCGImageAlphaPremultipliedLast);
CGColorSpaceRelease(colorspace);
if (context == NULL)
// если неполучилось создать контекст по какой либо причине отдатим nil
return nil;
CGContextScaleCTM(context, -1.0, -1.0);
CGContextTranslateCTM(context, -bounds.size.width, -bounds.size.height);
CGContextConcatCTM(context, transform);
//Отрисовка изображения в графический контекст в памяти
CGContextDrawImage(context, CGRectMake(0,0,width, height), imgRef);
CGImageRef imgRef2 = CGBitmapContextCreateImage(context);
CGContextRelease(context);
free(bitmapData);
UIImage * image = [UIImage imageWithCGImage:imgRef2 scale:initImage.scale orientation:UIImageOrientationUp];
NSData *newimageData = UIImageJPEGRepresentation(image,1.0);
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:newimageData  forKey:@"chosed_image_data"];
CGImageRelease(imgRef2);
return image;
}
Во время выполнения этого метода может быть некая задержка в приложении, так как идёт выделение памяти и устройство в отличии от эмулятора может слегка притормозить свою активность, поэтому нужно быть готовым к этому. Итак мы имеем универсальный метод по развороту картинки на 90 и 180  градусов в любую сторону, а также возможность зеркально отобразить изображения. При этом сохраняя его в контексте. Чем это лучше чем просто трансформация в виде анимации? Потому, что после например анимированного траснформа поворота мы получим картинку повернутую на 90 градусов, но в контексте она останется в прежнем состоянии. И при повторном выполнении трансформации мы получим тот же результат – картинку развернутую на 90 градусов, а не на 180 как задумывалось.

Пропорциональное изменение размеров изображений в IOS IPhone

Статья посвящена теме об пропорциональном изменении размеров фотографий в вашем приложении для IPone IPad. Так как в большинстве приложений по работе  с фотографиями рано или поздно разработчик сталкивается с задачей уменьшить или увеличить размер фото согласно заданным величинам ширины или величины. И уменьшение необходимо сделать пропорционально например ширине как это зачастую бывает. Так как если просто накинуть пару сотен пикселов ширине или высоте картинки полученное изображение может иметь искажённый вид, например растянуто по высоте. Это может и сойдет если работа идет с объектами типа дерево или куст, но никак не удовлетворит заказчика если вы работаете с фотографиями людей. А также возможно вам просто необходимо уменьшить размеры фото что бы не тратить драгоценный мобильный трафик при передаче фотографии друзьям.

Итак сама реализация:
Как обычно предполагаю что у вас уже есть проект с созданным в storyboard UIImageView для работы с изображениями. viewDidLoad я подгружаю картинку из проекта
UIImage *img = [UIImage imageNamed:@"test.png"];
mainimage.image = img;
где mainimage это ваш UIImageView
Теперь напишем метод в который можно привязать к кнопке, по нажатию на котороую мы уменьшаем реальный размер фото пропорционально по ширине до 640px.
-(IBAction) scale:(id)sender{
// создаем объект класса CGSize что бы задать пропорции нового фото
// первый параметр это ширина второй высота, но играет роль только размер для ширины так как метод ориентирован именно на пропорциональное уменьшение/увеличение по ширине
CGSize sz = CGSizeMake(640, 640);
UIImage *img = [UIImage imageNamed:@"test.png"];
UIImage *newimage = [self ScaleImgPropoWidth:img scaledToSize:sz];
mainimage.image = newimage;
}
Как вы видите реализация скрыта в методе ScaleImgPropoWidth, давайте посмотрим на реализацию метода:
- (UIImage *)ScaleImgPropoWidth:(UIImage *)image scaledToSize:(CGSize)newSize {
double ratio;
double delta;
CGPoint offset;
//проверка на то если новый размер картинки больше или равен старому то вернуть ту же картинку
if(newSize.width>=image.size.width){
return image;
}//если данная проверка вам ненужна вы можете её убрать, напрмиер если хотите в любом случае кропить размер или же при увеличении размеров заменить условие на if(newSize.width<=image.size.width)
ratio = newSize.width / image.size.width;
delta = (ratio*image.size.height – ratio*image.size.width);
UIImage *scaledImage =
[UIImage imageWithCGImage:[image CGImage]
scale:(image.scale / ratio)
orientation:(image.imageOrientation)];
CGRect clipRect = CGRectMake(0, 0,
scaledImage.size.width,
scaledImage.size.height);
CGSize sz = CGSizeMake(newSize.width, scaledImage.size.height);
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(sz, YES, 0.0);
} else {
UIGraphicsBeginImageContext(sz);
}
UIRectClip(clipRect);
[image drawInRect:clipRect];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
Как вы могли заметить преобразовании резамера происходит в графическом контексте, то есть это не просто трансформация изображения.

UITableView в нутри UIViewContrloller. IOS программирование

В этой статье я опишу как сделать полноценную таблицу UITableView  в вашем UIViewController. Так как работать с UITableViewController несколько сложнее. Этот метод поможет вам сэкономить время. Пример будет показана на основе работы с Xcode 4.6 и использованием stroryboard. Удобство такого метода даёт возможность размещать на вашем UIViewController и другие элементы кроме таблици UITableView, такие как NavigationBar или UITabbar  и они будут нормально смотрется, а не ездить за последней строчкой таблици(вдруг кто сталкивался с проблемой).  Для начала вам необходимо создать проект, описывать эти простые действия я не буду так как в интернетах полно документации как это сделать. И так разместите на вашем UIViewController элемент UITableView как показано на рисунке:


Теперь создайте класс в своем приложении или используйте класс который создал за вас Xcode. Я назвал свой katalog. Привяжите его к вашему UIViewController если это все таки новый класс и новый UIViewController. Иначе если вы используете уже созданный то делать этого не придется.
Теперь необходимо немного модифицировать h файл:
вот мой katalog.h
#import
@interface katalog : UIViewController {
IBOutlet UITableView *table;
}

@end
Обратите внимание на это означает, что этот класс будет делегатом для таблици и источником данных.
IBOutlet UITableView *table; это аутлет для нашего UITableView его нужно подвязать к таблице нажатием правой кнопкой мыши на элементе UITableView и перетянув от New Referencing Outler  к вашему класу в левой колонке где показаны все Scene – активности вашего приложения.
Теперь приступим к реализации нашего m файла, в моём случае это katalog.m. В метод - (void)viewDidLoad я добавил 2 строки:
[table setDelegate: self];
[table setDataSource: self];
Указывая уже объекту table  кто будет делегатом и источником данных для него (по сути для таблици).
Поскольку наш класс является делегатом и источником данных для таблици необходимо реализовать стандартные методы для UITableView, изначально в m файле их нет поэтому придется добавить. В таблице будет две секции без названия и в каждой их них по одной строке с какими либо данными. Все это опишем в методах таблици.
Вот листинг кода который необходимо добавить в m файл:
#pragma mark – Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
#warning Potentially incomplete method implementation.
// Количество секций в таблице.
return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
#warning Incomplete method implementation.
// Вернуть количество строк в секции.
return 1;
}
/*
Сформировать строки таблици
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSString *lang = [userDefaults objectForKey:@"lang"];
static NSString *CellIdentifier = @»Cell»;
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] ;
}
if(indexPath.row==0 && indexPath.section==0){
cell.text = @»Первая строка»;
//сформировать дату и перевести её в строку
//это просто пример какие данные можно добавить в таблицу
NSDate *d = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd_HH:mm:ss"];
[formatter setTimeZone:[NSTimeZone timeZoneWithName:@"..."]];
NSString *date = [formatter stringFromDate:d];
cell.detailTextLabel.text = date;
}else if(indexPath.section==1){
cell.text = @»Вторая строка»;
cell.detailTextLabel.text = @»ваши данные»;
}
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
#pragma mark – Table view delegate
/*
Обработка событий нажатия на строки таблици
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row==0 && indexPath.section==0){
//нажали на первую строку в первой секции
}else{
//нажали на другую строку
}
}

Конечно неплохо было бы изменить немножко внешний вид таблицы, для этого в настройках UITableView в storyboard и поставил опцию Grupped в параметре Style как показано на рисунке:

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

UITableView в нутри UIViewContrloller. Часть 2 – большие списки

В предыдущей части я описывал как создавать таблицы внутри UIViewContrloller, простейшим способом. Теперь поговорим о создании таблиц с большим количеством строк и сложными механизмами их формирования. Как создать проект и разместить UITableView описывать не буду можете посмотреть в предыдущей части. В данном примере мы будем выводить большое количество данных в качестве строк в таблицу. Для начала подправим наш h файл, если помните у меня это попрежнему katalog.h вот как он будет выглядеть:
#import
@interface katalog : UIViewController {
IBOutlet UITableView *table;
}
@property (strong,nonatomic)NSMutableArray* listOfItems;
-(void) prepereList;
@end

На самом деле я добавил только свойство listOfItems в качестве данных для него будет некий массив элементов в последствии строк. И добавил еще вспомогательный метод -(void) prepereList; – который будет готовить данные для выгрузки в таблицу, собственно наполнять listOfItems.
Релизация этого метода в m файле:
-(void) prepereList{
NSMutableArray *marray = //предположим что такой массив данных у вас есть, если нет то можете воспользоватся любыми примерами по формированию данных этого типа
//создадим объект типа массив для ключей уже существующих  значений из marray нашего массива данных строк
NSArray *keylist = [[NSArray alloc] initWithArray:marray];
//объявим наше свойство listOfItems.
listOfItems = [[NSMutableArray alloc] init];
NSDictionary *emDict = [NSDictionary dictionaryWithObject:keylist forKey:@"Sometext"]; //создадим ключ секцию и в качестве NSDictionary сохраним объект массив
//присвоим данные нашему списку элементов таблици
[listOfItems addObject:emDict];
}
Также не забудьте сделать @synthesize listOfItems;
Конечно кажется что метод несколько замутный и излишне орудует массивами. Дело в том что именно этот способ подходит мне для дальнейшей работы с данными, если захотите его упростить то можете это делать.
Далее незабываем включить наш метод в метод viewDidLoad
- (void)viewDidLoad
{
[super viewDidLoad];
[table setDelegate: self];
[table setDataSource: self];
[self prepereList];
}
Несколько изменятся методы по работе с таблицей относительно первой статье:
#pragma mark – Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [listOfItems count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSDictionary *dictionary = [listOfItems objectAtIndex:section];
NSArray *array = [dictionary objectForKey:@"Sometext"];
NSLog(@»%d»,[array count]);
return [array count];
}
/*
Сформировать строки таблици
*/
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @»Cell»;
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] ;
}
NSDictionary *dictionary = [listOfItems objectAtIndex:indexPath.section];
NSMutableArray *marray = [dictionary objectForKey:@"Sometext"];
NSDictionary *d = [marray objectAtIndex:indexPath.row];
NSString *code =  [d valueForKey:@"code"];
cell.text = @»Maintext»;
UIFont *myFont = [ UIFont fontWithName: @"System" size: 17.0 ];
cell.textLabel.font = myFont;
cell.tag = 1;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.detailTextLabel.text = @»datail»;
return cell;
}
#pragma mark – Table view delegate
/*
Обработка событий нажатия на строки таблици
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if(indexPath.row==0 && indexPath.section==0){
//нажали на первую строку в первой секции
}else{
//нажали на другую строку
}
}
Немного не понятно откуда берутся данные, но сама реализация направлена на то, что бы показать как вывести большое количество строк автоматически, а не на то как сформировать данные для таблицы. Так что уж простите что не акцентирую внимание на этом.

Есть ещё один метод для формирования заголовков секций таблици, можете добавить его прямо в m  файд:
/**
заголовки секций
*/
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
NSString *sectioname = @»Заголовок»;
return sectioname;
}
Вызов этого метода генерирует сам TableView, и искать его он будет в нашем классе, так как именно наш класс katalog.m – делегат таблици. В качестве входного параметра section используется номер секции, в данном примере у меня одна секция и проверять это значения смысла нет. Поэтому я просто верну  название строкой. Можете скомпилировать проект и посмотреть как изменится вид таблици, над списокм появится заголовок.

Objective C регулярные выражения. NSRegularExpression поиск совпадений

Конечно же в разработке мобильных приложений под IPhone Ipad встречаются случаи когда необходимо использовать регулярные выражения. Сегодня я опишу метод и саму работу с регулярными выражениями для поиска совпадений в тексте. Для начала реализуйте метод описанный в листинге наже:
//в качестве входного параметра мы передаём в метод текст в котором необходимо найти совпадния
-(NSArray*) getMatchesfromstr:(NSString *)text{
/*пускай мы будем искать в тексте маркировку бензина А92 или А95 или А 80*/
NSRegularExpression *nameExpression = [NSRegularExpression regularExpressionWithPattern:@"(A ?[0-9]{2})» options:NSRegularExpressionSearch error:nil];
NSArray *matches = [nameExpression matchesInString:text
options:0
range:NSMakeRange(0, [text length])];
//на выходе получим массив найденных элементов
return matches;
}
Как видите метод не сложный для понимая основан на использовании NSRegularExpression, Далее посмотрим сам вызов и использование метода.

Итак добавим следующий код в нужный вам метод:
NSString *text = @»Текст для проверки и поиска бензана A92 или же с пробелом А 80.»;
//собственно вызов метода
NSArray *matches = [self getMatchesfromstr:text];
// проверяем найдено ли что либо
if([matches count]>0){
//далее цикл перебора элементов
for (NSTextCheckingResult *match in matches) {
NSRange matchRange = [match rangeAtIndex:0];
NSString *matchString = [text substringWithRange:matchRange];
NSLog(@»%@»,matchString);
}
}
Вот собственно и все, мы нашли совпадения и вывели их в лог. Дальше как с ними работать вам решать.