10 сентября 2013 г.

Динамическое добавление swap в Linux

Сегодня, на очень короткое время на компьютере понадобилось добавить swap, переразбивать ради этого диск с системой совсем не хотелось. Оказывается в Linux можно создать файл и сказать системе использовать его как своп. Спасибо блогу за простое решение.
$ free -m
 total used free shared buffers cached
Mem: 2018 1225 793 0 7 335
-/+ buffers/cache: 882 1135
Swap: 2957 124 2832
$ dd if=/dev/zero of=swap.swap bs=1M count=100
100+0 записей считано
100+0 записей написано
скопировано 104857600 байт (105 MB), 0,768403 c, 136 MB/c
$ mkswap swap.swap
Устанавливается пространство для свопинга версии 1, размер = 104853 кБ
без метки, UUID=1b3f8a75-8214-406b-9841-a5f82bf56ae8
$ sudo swapon swap.swap
$ free -m
 total used free shared buffers cached
Mem: 2018 1327 691 0 7 436
-/+ buffers/cache: 883 1135
Swap: 3057 124 2932
и для удаления
$ sudo swapoff swap.swap
$ rm swap.swap
$ free -m
 total used free shared buffers cached
Mem: 2018 1239 778 0 8 348
-/+ buffers/cache: 883 1135
Swap: 2957 124 2832

27 апреля 2013 г.

Смена ориентации экрана в модальном окне iOS 5/6

Случилось мне недавно делать приложение для iOS, которое работает в портретной ориентации экрана и только одно вью (которое отображалось модально) нужно было отображать только в ландшафтной ориентации экрана. Что ж, решение для iOS 5.х довольно простое: в методе - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation модального окна просто прописываем нужный разворот устройства

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
    return (toInterfaceOrientation == UIInterfaceOrientationLandscapeRight);
}


Для iOS 6.x все оказалось немного сложнее:

1. В классе вью контроллера модального окна определяем обработчики методов

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
 return UIInterfaceOrientationLandscapeRight;
}

- (NSUInteger)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscape;
}

- (BOOL)shouldAutorotate
{
    return YES;
}


2. Сразу после вызова показа модального окна устанавливаем положение статус бара:

 [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationLandscapeRight animated:NO];


3. Перед тем, как убрать модальное окно, возвращаем статус бар в нужное положение:

 [[UIApplication sharedApplication] setStatusBarOrientation:UIInterfaceOrientationPortrait animated:NO];


Как обычно пример на github-е.

16 декабря 2012 г.

UIDatePicker как клавиатура для UITextField

Цель: сделать удобной выбор даты в UITextField, будем использовать UIDatePicker
Алгоритм: перехватим событие - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField у UITextField и вместо показа системной клавиатуры, покажем наше вью.

Думаю не стоит описывать процесс создания и назначения делегата у UITextField, это можно сделать как в Interface Builder-е так и динамически. Сразу смотрим метод делегата -(void)textFieldDidBeginEditing:(UITextField *)textField:

- (void)textFieldDidBeginEditing:(UITextField *)aTextField
{
 [aTextField resignFirstResponder];
 
 [_pickerViewPopup release];
 _pickerViewPopup = [[UIActionSheet alloc] initWithTitle:nil delegate:nil cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
 
 [_pickerView release];
 _pickerView = [[UIDatePicker alloc] initWithFrame:CGRectMake(0.0, 44.0, 0.0, 0.0)];
 _pickerView.datePickerMode = UIDatePickerModeDate;
 _pickerView.hidden = NO;
 _pickerView.date = [NSDate date];
 [_pickerView addTarget:self action:@selector(dateChanged) forControlEvents:UIControlEventValueChanged];
 
 UIToolbar *pickerToolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 44.0)];
 pickerToolbar.barStyle = UIBarStyleBlackOpaque;
 [pickerToolbar sizeToFit];
 
 NSMutableArray *barItems = [[NSMutableArray alloc] init];
 
 UIBarButtonItem *flexSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
 [barItems addObject:flexSpace];
 [flexSpace release];
 
 UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneButtonPressed:)];
 [barItems addObject:doneBtn];
 [doneBtn release];
 
 UIBarButtonItem *cancelBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelButtonPressed:)];
 [barItems addObject:cancelBtn];
 [cancelBtn release];
 
 [pickerToolbar setItems:barItems animated:YES];
 [barItems release];
 
 [_pickerViewPopup addSubview:pickerToolbar];
 [_pickerViewPopup addSubview:_pickerView];
 [_pickerViewPopup showInView:self.window];
 [_pickerViewPopup setBounds:CGRectMake(0.0, 0.0, 320.0, 464.0)];
 [pickerToolbar release];
}


тут мы создаем модальное окно, на основе UIActionSheet и в него вставляем UIDatePicker и UIToolbar с кнопками "Ok" и "Cancel".

И события нажатия на эти кнопки:

- (void)doneButtonPressed:(id)sender
{
 self.dt = [_pickerView date];
 
 [_pickerViewPopup dismissWithClickedButtonIndex:1 animated:YES];
 [_pickerView removeTarget:self action:@selector(dateChanged) forControlEvents:UIControlEventValueChanged];
}

- (void)cancelButtonPressed:(id)sender
{
 [_pickerViewPopup dismissWithClickedButtonIndex:1 animated:YES];
 [_pickerView removeTarget:self action:@selector(dateChanged) forControlEvents:UIControlEventValueChanged];
}


В обоих случаях скрываем наше "модельное" окно и отписываемся от события получения нотификации о изменении даты на UIDatePicker. А при нажатии на "Ok" так-же сохраняем выбранную дату на "барабане".

И событие изменения даты на UIDatePicker для изменения даты так-же в текстовом поле:

- (void)dateChanged
{
 NSDateFormatter *df = [[NSDateFormatter alloc] init];
 [df setDateFormat:@"dd.MM.yy"];
 _tf.text = [df stringFromDate:[_pickerView date]];
}


Проект на github-е. Утащено с stackoverflow.

9 декабря 2012 г.

Применение изображения-маски на UIView

После длительного перерыва решил опубликовать новый пост в блоге.

Традиционно все UIView в iOS имеют прямоугольную форму. И с помощью полупрозрачного цвета (так-же изображений с alpha каналом) и порядком (z-order) наложения вью друг на друга можно добиваться практически всего, что можно вообразить. Но вот понадобился мне полупрозрачный свой UISwitch в котором был предопределен порядок вьюшек.

И что б этот пост не был постом об одном методе, опишу процесс создания компоненты.

Есть изображения:

1. подложка компоненты

2. маска под эту подложку

3. включенное и выключенное состояния

Наследоваться будем от UIView.

В методе init будем создавать вью которые нам и понадобятся.

  _backgroundImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"butt_bg"]];
  [self addSubview:_backgroundImage];


создаем подложку компоненты и добавляем ее на родительское вью

  UIView *maskedView = [[UIView alloc] initWithFrame:self.bounds];
  maskedView.backgroundColor = [UIColor clearColor];
  [self addSubview:maskedView];


создаем вью, к которому будет примененна маска, на него будем ложить дальше компоненты для того, что б они не вылазили за пределы внутреннего "овала"

  _backgroundView = [[UIScrollView alloc] initWithFrame:self.bounds];
  _backgroundView.backgroundColor = [UIColor clearColor];
  _backgroundView.clipsToBounds = YES;
  _backgroundView.delegate = self;
  _backgroundView.clearsContextBeforeDrawing = NO;
  _backgroundView.pagingEnabled = YES;
  _backgroundView.showsVerticalScrollIndicator = NO;
  _backgroundView.showsHorizontalScrollIndicator = NO;
  _backgroundView.scrollsToTop = NO;
  _backgroundView.contentSize = CGSizeMake(105.0, _backgroundView.bounds.size.height);
  _backgroundView.bounces = NO;
  [maskedView addSubview:_backgroundView];
  
  _onLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  _onLabel.backgroundColor = [UIColor clearColor];
  _onLabel.opaque = NO;
  _onLabel.textColor = [UIColor blackColor];
  _onLabel.font = [UIFont boldSystemFontOfSize:16.0];
  _onLabel.textAlignment = UITextAlignmentCenter;
  _onLabel.text = NSLocalizedString(@"ON", nil);
  _onLabel.frame = CGRectMake(0.0, 0.0, 43.0, _backgroundView.frame.size.height);
  [_backgroundView addSubview:_onLabel];

  UIImage *img = [UIImage imageNamed:@"r_butt_on"];
  _ballImage0 = [[UIImageView alloc] initWithImage:img];
  _ballImage0.frame = CGRectMake((_backgroundView.contentSize.width-img.size.width)/2.0,
           (_backgroundView.contentSize.height-img.size.height)/2.0,
           img.size.width, img.size.height);
  [_backgroundView addSubview:_ballImage0];
  
  img = [UIImage imageNamed:@"r_butt_off"];
  _ballImage1 = [[UIImageView alloc] initWithImage:img];
  _ballImage1.frame = _ballImage0.frame;
  _ballImage1.alpha = 0.0;
  [_backgroundView addSubview:_ballImage1];
  
  _offLabel = [[UILabel alloc] initWithFrame:CGRectZero];
  _offLabel.backgroundColor = [UIColor clearColor];
  _offLabel.opaque = NO;
  _offLabel.textColor = [UIColor blackColor];
  _offLabel.font = [UIFont boldSystemFontOfSize:16.0];
  _offLabel.textAlignment = UITextAlignmentCenter;
  _offLabel.text = NSLocalizedString(@"OFF", nil);
  _offLabel.frame = CGRectMake(60.0, 0.0, 43.0, _backgroundView.frame.size.height);
  [_backgroundView addSubview:_offLabel];


тут _backgroundView - скролл который будет анимированно двигаться, котда будем прикасаться к нему, на нем лежит две текстовые метки: _onLabel и _offLabel которые просто отображают текст и вьюшки с включенной и выключенной лампочками (_ballImage0 и _ballImage1).

А вот и подобрались к самому главному, создаем слой маски из изображения и применяем его к вью:

  UIImage *_maskingImage = [UIImage imageNamed:@"butt_mask"];
  CALayer *_maskingLayer = [CALayer layer];
  _maskingLayer.frame = CGRectMake(1.0, 1.0, self.bounds.size.width-2.0, self.bounds.size.height-2.0);
  [_maskingLayer setContents:(id)[_maskingImage CGImage]];
  maskedView.layer.mask = _maskingLayer;



Регистрируем слушателя на касание внутри нашей компоненты:

UITapGestureRecognizer *singleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; [self addGestureRecognizer:singleFingerTap]; [singleFingerTap release];

и обработчик этого одиночного касания (до этого мы все делали в методе init):

- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
 [self setOn:!_on animated:YES];
}


так-же методы установки/получения состояния компоненты:

- (void)setOn:(BOOL)on animated:(BOOL)animated
{
 _on = on;
 _scrollingAnimation = animated;
 [_backgroundView setContentOffset:CGPointMake(on?0.0:_backgroundView.contentSize.width-self.bounds.size.width, 0.0) animated:animated];
 _ballImage0.alpha = _on?1.0f:.0f;
 _ballImage1.alpha = _on?.0f:1.0f;
}

- (void)setOn:(BOOL)on
{
 [self setOn:on animated:NO];
}

- (BOOL)on
{
 return _on;
}



тут в зависимости от состояния меняем прозрачность наших изображений _ballImage0 и _ballImage1 ну и храним состояние в переменной _on

и обработчики перемещения UIScrollView пользователем:

- (void)scrollViewDidScroll:(UIScrollView *)sender
{
 CGFloat koof = sender.contentOffset.x/(sender.contentSize.width-sender.bounds.size.width);
 _ballImage0.alpha = 1.0f-koof;
 _ballImage1.alpha = koof;
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
 if (!_scrollingAnimation)
 {
  self.on = _backgroundView.contentOffset.x<1.0;
 }
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
 if (!decelerate && !_scrollingAnimation)
 {
  self.on = _backgroundView.contentOffset.x<1.0;
 }
}


Вот и все, проект можно посмотреть на github-е, в нем специально закомментирована строка _backgroundView.bounces = NO;, для более наглядной демонстрации эффекта.

ЗЫ: Вот еще одно интересное применение маски.

6 августа 2012 г.

Создание пользователя Samba в Ubuntu

Как-то в последнее время не получается писать сюда. Оправдываться не буду, потому-что в борьбе с ленью она пока одерживает верх. Но будут и еще битвы в которых я уж точно не проиграю.

В данный момент заканчиваю приложение для конвертирования видео для iOS устройств под OS X и тут будет о чем написать.

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

Создаем пользователя самбы и задаем ему пароль:
$ sudo smbpasswd -a <sambausername>

Редактируем (или если нет - создаем) файл /etc/samba/smbusers, который имеет вид <ubuntuusername> = “<sambausername>”, т.е. задает соответствие пользователя самбы и пользователя системы.

После всех манипуляций перегружаем демона самбы:
$ sudo /etc/init.d/smbd restart

6 марта 2012 г.

Перехват двойного тапа у UIWebView

В классе, который будет обрабатывать двойной тап по UIWebView регистрируем обработчик двойного тапа, если это UIViewController то, например, в методе viewDidLoad:
- (void)viewDidLoad
{
    UITapGestureRecognizer *doubleFingerTap = [[UITapGestureRecognizer alloc]
                                                initWithTarget:self action:@selector(handleDoubleTapGesture:)];
    doubleFingerTap.numberOfTapsRequired = 2;
    doubleFingerTap.delegate = self;
    [self.webView addGestureRecognizer:doubleFingerTap];
    [doubleFingerTap release];
}

и
#pragma mark Gesture recognizer delegate

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer 
{
    return YES;
}

так-же и сам метод, который будет вызываться при двойном тапе:
- (void) handleDoubleTapGesture:(UITapGestureRecognizer *) gestureRecognizer
{
    if (gestureRecognizer.state == UIGestureRecognizerStateEnded)
 {
...
 }
}

Ну и на последок, в *.h-файл нашего класса, добавляем описание поддержки протокола
<UIGestureRecognizerDelegate>

1 ноября 2011 г.

Перенос базы MySQL c одного сервера на другой

Пост немного оффтоп, да и в поисковике довольно быстро решение ищется, но сегодня решил опубликовать, что было "под рукой". Допустим к каждому серверу есть доступ к консоли.

На первом сервере делаем дамп базы
$ mysqldump -u[логин] -p[пароль] [базаданных] > mybase.sql

переписываем этот дамп на второй сервер, и делаем экспорт:
$ mysql -u[логин] -p[пароль] [базаданных] < mybase.sql

1 октября 2011 г.

UIGestureRecognizer перехват одиночного касания и двойного на одном UIView

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

В этом случае нужно запретить в UIGestureRecognizer одиночного тапа посылку события при двойном тапе. Делается просто методом - (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer.

Пример:
        UIGestureRecognizer *doubleTapGestureRecognizer = [[UIGestureRecognizer alloc]
                                initWithTarget:self action:@selector(handleDoubleTap:)];
        doubleTapGestureRecognizer.numberOfTapsRequired = 2;
        [self addGestureRecognizer:doubleTapGestureRecognizer];

        UIGestureRecognizer *singleTapGestureRecognizer = [[UIGestureRecognizer alloc]
                                                              initWithTarget:self action:@selector(handleSingleTap:)];
        singleTapGestureRecognizer.numberOfTapsRequired = 1;
        [singleTapGestureRecognizer requireGestureRecognizerToFail:doubleTapGestureRecognizer];
        [self addGestureRecognizer:singleTapGestureRecognizer];

8 сентября 2011 г.

Отключение ARC в xCode 4.2

Нужно всего лишь в качестве компилятора в свойствах проекта выбрать "LLVM GCC 4.2" вместо установленного по умолчанию "Apple LLVM compiler 3.0".



PS: По совету твиттер пользователя @iLeNsTR можно обойтись флагами компилятора: