Category: iOS

  • SQLite FMDB Batch / Bulk Inserts

    SQLite
    I use FMDB framework to work with SQLite database on iOS. Sometimes you need to insert many rows, many objects that come from a server to your local database. It can take some time. When I was inserting rows one by one, the method took 50 seconds to finish inserting about 1300 rows. So I decided to find a faster solution.

    And found it here. To insert many rows faster you should use transactions. It is very easy, you shouldn’t use complex approaches, like preparing huge SQL statements. I got 0.5 seconds as a result on iPhone 3GS. Here is more sophisticated approach to optimize insert of millions of rows, but it’s not my case, I’m satistfied with 0.5 second result.

    _72483466_clockthinkstock

    This is a sample code:

    + (BOOL)addToDbRegionArray:(NSArray *)regionArray
    {
      FMDatabase *db = [[DBConnection sharedInstance] db];
      
      if ( ! [db open] ) {
        return NO;
      }
      
      [db beginTransaction];
      
      for (RRRegion *region in regionArray) {
        [db executeUpdate:@"INSERT INTO regions (region_id, name, city_id, country_id, has_metro, is_popular) VALUES (?, ?, ?, ?, ?, ?);" withArgumentsInArray:@[@(region.sid), region.name, @(region.cityId), @(region.countryId), @(region.hasMetro), @(region.isPopular)]];
      }
      
      [db commit];
      [db close];
      
      return YES;
    }
    

    I have a class RRRegion, which objects I am inserting. I open database, then begin a transaction, execute as many updates as I have objects and commit a transaction, close database.

    I should mention, that when I was using caching of statements by FMDB, I got strange leak statement errors, so I don’t cache them. I don’t have this line:

    [db setShouldCacheStatements:NO];
    

    This is how I measured the time it takes:

    NSDate *start = [NSDate date];
    NSArray *jsonArray = (NSArray *)JSON;
    NSMutableArray *regionArray = [NSMutableArray new];
    for (NSDictionary *jsonDic in jsonArray) {
      RRRegion *region = [[RRRegion alloc] initFromDic:jsonDic];
      [regionArray addObject:region];
    }
    
    [RRRegion addToDbRegionArray:regionArray];
    
    NSDate *finish = [NSDate date];
    NSTimeInterval interval = [finish timeIntervalSinceDate:start];
    NSLog(@"Time consumed to add regions: %f", interval);
    
  • Sending iOS Push Notifications using Python module PyAPNS

    python-django

    I have written a small module, that sends a push notification using PyAPNS.

    This is how my sender.py module looks like:

    # -*- coding: utf-8 -*-
    from django.db import connection
    from apns import APNs, Frame, Payload
    
    
    class Sender:
    	def send(self):
    		apns = APNs(use_sandbox=True, cert_file='Cert.pem', key_file='Key.pem')
    		token_hex = 'e4d4e96ec8ac3dd003e0129347b3421fe53ba49811b3803c4e99cfdc60293c94'
    		message = "Hello"
    		payload = Payload(alert=message.decode('utf-8'), sound="default", badge=0)
    		apns.gateway_server.send_notification(token_hex, payload)
    

    Here is a Sender class inside sender.py module. It has one method send. Inside this method I create an object of APNs class, create a payload and send it using this object.
    Cert.pem and Key.pem files are inside the folder with this module. They can be created using this tutorial. Also that folder contains apns.py module file with PyAPNS code.

    To send a sample push notification from a command line I use following commands. First, I enter the folder with module. It is called notification_sender:

    $ cd ~/Documents/common-app-server/app_server/notification_sender
    

    Or on server:

    # cd ~/www/den.ladby.ru/public/common-app-server/app_server/notification_sender
    

    Then I enter to the python console:

    $ python
    

    Then I import Sender class from sender module:

    from sender import Sender
    

    Create a sender object of a Sender class:

    sender = Sender()
    

    And finally send a notification:

    sender.send()
    

    All you need to do to finish the job is to enter a PEM pass phrase:

    Enter PEM pass phrase:
    

    Currently, the device token is hardcoded, I am planning to use SQLite entries with collected tokens. I use Django to collect tokens.

    I would like to add that if you change somehow the source file of a module, you should reenter python console and recreate object to make changes work.

  • Краткое введение в push-уведомления на iOS

    Иногда нужно сообщить пользователю мобильного приложения о каком-то интересном событии. Таким событием может быть появление нового сообщения для пользователя. При этом, если приложение будет постоянно висеть в фоне и проверять периодически сервер, то это будет крайне неэкономно с точки зрения заряда батареи. Поэтому и придумали push – уведомления. Это сообщения от сервера, которые приходят на телефон пользователя, даже когда приложение не запущено. Отправлять их должен ваш сервер, но не напрямую на телефоны всех пользователей, а через специальные сервера Apple, которые называются APNS – Apple Push Notification Servers. Работают они так:

    Push-Overview-467x500

    Что нужно, чтобы отправить push – уведомление с сервера на APNS?

    1. Сертификат и ключ к сертификату для данного приложения. iOS-разработчик может их предоставить. См. туториал ниже по их генерации.
    2. Токен устройства. Это хеш-код, который идентифицирует данное устройство в связке с приложением на APNS. Токены нужно собирать в отдельную таблицу на вашем сервере. Для этого необходимо разработать API запрос, по которому iOS-разработчик сможет отправлять на сервер связку токен устройства – имя пользователя или просто токен устройства. Токен может отправляться на ваш сервер при каждом запуске приложения. При получении на сервере соответствующую запись нужно обновлять.
    3. JSON с описанием уведомления. Зная токен для данного пользователя и имея сертификат, можно сформировать JSON специального вида, содержащий текст уведомления и отправить его по SSL на APNS. APNS дальше уже отсылает уведомление на телефон. Имея токены, можно разрабатывать и отправлять с сервера любые push – уведомления, которые потребуются. Для Python уже есть готовые библиотеки для отправки push – уведомлений. Я полагаю, что для PHP, они наверняка тоже есть, так что тут лучше с нуля код полностью не писать и не тратить силы.

    JSON может иметь разную конфигурацию в зависимости от ваших потребностей. Полное описание смотрите в документации. Ссылка ниже.

    Пример JSON:

    {
    	"aps":
    	{
    		"alert": "Hello, world!",
    		"sound": "default"
    	}
    }
    

    Другой вариант:

    {
    	"aps":
    	{
    		"alert":
    		{
    			"action-loc-key": "Open",
    			"body": "Hello, world!"
    		},
    		"badge": 2
    	}
    }
    

    Здесь badge – это номер, который появится на иконке приложения после прихода уведомления. Он может быть равен например числу новых сообщения для пользователя.
    body – текст уведомления

    Подробнее:

    Apple Push Notification Service

    Tutorial

    Написал ТЗ для нашего серверного разработчика на работе и решил перенести часть его сюда, так как ТЗ большей частью представляет из себя популярное изложение того, что такое push-уведомления и как их создавать на сервере.

    Немаловажный аспект: push-уведомления являются бесплатным сервисом от Apple, то есть за эксплуатацию APNS платить не надо. Вся стоимость их поддержки – это стоимость поддержки вашего сервера. Но даже так, они могут оказаться дорогим удовольствием, особенно если вы платите за мощности в облаке. Также стоит еще раз сказать, что для отправки push-уведомлений необходим SSL, который не все облачные сервисы предоставляют бесплатно.

  • Searching for the best technology for a mobile app backend development

    Client-server applications with a mobile app client are more interesting than mobile standalone applications. They offer a new type of features for users like daily updated content. That is why at some moment of my mobile developer career I decided to learn how to create a server side for my mobile applications myself. As it happens usually in IT, there were a lot of techologies and programming languages, that I could start to learn and use for achieve my goals. Of course, if I would stop on the first one, that I have tried, I would lose, because one can never find the best way without understanding what other ways give and without any broad enough knowledge. I think, it is a good idea to get familiar with minuses of each technology before starting to learn and use it.

    This is my story. I started with Java Servlets and I have tried also PHP and Python at the moment. Also I have read about Ruby On Rails and Node.JS. Finally, I stopped currently at using Python with Django.

    Between Java Servlets and Python I choose Python. Development on Python it is much faster than on Java Servlets. It has no complex and sensible configuration files. Python offers iterative development, you can just refresh a web page and see results instantly. With Java Servlets you have to wait some time every time you update something. Python is like scripting language, despite it is compiled to some kind of byte code. I also liked python for it’s clean syntax, despite I am friendly with Java too. Using HTML templates with Python is easier to me, than creating JSP pages with servlets. Just for information, I use Sublime Text 2 as a Python editor with a Lazy color theme. It is really convenient editor.

    I will not try PHP, because it is not valuable now, loses it’s popularity. It looks like Python offers almost the same features but even is better because of syntax, because it is compiled and because it offers full OOP support from the start and you can create all kind of applications including desktop applications with it. Also there are a lot of scientific and data analysis libraries on Python, that can be useful to create sophisticated back-end.

    I don’t like the idea of using generally considered to be slow Javascript at the backend in Node.js. Also Node.js needs it’s own HTTP server.

    What about Parse, QuickBlox and other ready for use backend services? I don’t want to use them, because I want to be able to create my own-backends with complete understanding of their code and work. These are good to create something easy and usual, but not something unique.

    Probably I will try also Ruby on Rails at some moment.

    But currently I am completely satisfied with Python. I want to get familiar with Django framework on Python too.

    There are also open-source backends like Baasbox: http://www.baasbox.com/. But I haven’t tried it yet. Looks like it is written on Java, because needs JVM.

    More articles on this topic:

    http://www.raywenderlich.com/20482/how-to-choose-the-best-backend-provider-for-your-ios-app-parse-vs-stackmob-vs-appcelerator-cloud-and-more

    http://www.developer-tech.com/news/2013/feb/22/exploring-mobile-app-backend-options/

  • The best way to create Forms in iOS

    I think the best way to create forms in iOS is by using FXForms open-source project. It can be found in Github. There are some alternatives, but only FXForms support iOS 6. However, FXForms is still not flexible enough. So, if you want to create something completely custom by design, probably, it will not be a suitable solution.

    The main advantage of this approach is that your forms become very compact. Also you will save tons of time and your nerves creating many similar and boring forms after you understand how to use FXForms. But not so easy. The main difficulty is to learn how to declare fields.

    There are many examples in the project repository. This is not a tutorial, but rather an introduction. Basically what you do is you inherit from FXFormViewController to create a form view controller.

    #import "RRBaseTableViewController.h"
    #import "FXForms.h"
    
    @interface RRBaseAddResumeViewController : FXFormViewController  
    

    And you create a form object inheriting NSObject, that conforms to FXForm protocol.

    Header file:

    #import 
    #import 
    
    typedef NS_ENUM(NSInteger, Gender)
    {
      GenderMale = 0,
      GenderFemale
    };
    
    
    @interface RRCreateResumeForm : NSObject 
    
    @property (nonatomic, copy) NSString *surname;
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, copy) NSDate *birthday;
    @property (nonatomic, assign) Gender gender;
    
    @end
    

    Implementation file:

    #import "RRCreateResumeForm.h"
    
    @implementation RRCreateResumeForm
    
    
    - (NSArray *)fields
    {
      return @[
               @{FXFormFieldKey: @"surname", FXFormFieldTitle: @"Фамилия"},
               @{FXFormFieldKey: @"name", FXFormFieldTitle: @"Имя"},
               @{FXFormFieldKey: @"birthday", FXFormFieldTitle: @"Дата рождения"},
               @{FXFormFieldKey: @"gender", FXFormFieldOptions: @[@"Мужской", @"Женский"], FXFormFieldTitle: @"Пол"}
               ];
    }
    
    @end
    

    And this is how you stick FormViewController with it’s Form:

    - (void)createResumeClicked:(id)sender
    {
      RRCreateResumeViewController *createResumeViewController = [[RRCreateResumeViewController alloc] init];
      RRCreateResumeForm *form = [[RRCreateResumeForm alloc] init];
      createResumeViewController.formController.form = form;
      
      [self.navigationController pushViewController:createResumeViewController animated:YES];
    }
    
  • iOS State Restoration vs NSCoding

    My goal was to create a mechanism to store user interface state in my app. So I decided to study Apple’s State Preservation and Restoration, that was first introduced in iOS 6. As far, as I could understand on my own experience use:
    1. iOS State Preservation and Restoration, if you want to store navigation state in an app, that doesn’t change root controller of a window at some moment. It is convenient in this case.
    2. NSCoding Protocol for simpler tasks, when you don’t want to navigate, but want to save interface states for only several forms, because it is much more flexible – you completely control the process.

    I have tried to implement State Preservation and Restoration that was introduced in iOS 6 in my app but unfortunately I failed. The problem was that it’s mechanism is not flexible enough. It can restore state of View Controllers in a linear tree. But if your app as mine changes a Root Controller of your Window at some moment after user logins, for instance, this mechanism will not work. However, in other apps with simpler architecture it can be successfully used. It helps to bring a user right to the place where he stopped using your app last time even if app is removed from the background.

    There is a good presentation on this topic on SlideShare.

    I used this tutorial also. There is a code on GitHub, that works.

    However, there is a good flexible alternative: saving objects to text files using NSCoding protocol:

    - (void)viewDidLoad
    {
      [super viewDidLoad];
    
      // Restoring form object from the file
      NSString *formFilePath = [self formFilePath];
      RRCreateResumeForm *form = [NSKeyedUnarchiver unarchiveObjectWithFile:formFilePath];
      if (form != nil) {
        self.formController.form = form;
      }
    }
    
    
    - (void)viewWillDisappear:(BOOL)animated
    {
      [super viewWillDisappear:animated];
      
      // Saving the form object to the file
      NSString *formFilePath = [self formFilePath];
      [NSKeyedArchiver archiveRootObject:self.formController.form toFile:formFilePath];
    }
    
    
    // Returns a file path to the file with stored form data for form controller
    - (NSString *)formFilePath
    {
      NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
      NSString *documentsDirectory = [paths objectAtIndex:0];
      NSString *formClassName = NSStringFromClass( [self.formController.form class] );
      NSString *formFileName = [NSString stringWithFormat:@"%@.txt", formClassName];
      NSString *formFilePath = [documentsDirectory stringByAppendingPathComponent:formFileName];
      
      return formFilePath;
    }
    
  • Open-Source Android and iOS Projects

    I highly recommend you to look at popular open-source projects in your field even before you start developing something. Because almost everything you want to create is already created by the community with a very high quality. I understood this a year ago when I discovered Open source in iOS for myself and now I discovered it in Android. In this post I will give you a MUST look list of references and projects.

    A list of important and popular open-source projects on GitHub for Android and iOS can be found here:

    By best match:

    Android

    iOS

    By most stars:

    Android

    iOS

    By most forks:

    Android

    iOS

  • How to use a new model of CocoaPods PodSpec updates

    Recently CocoaPods started to use web service to load new PodSpecs.

    I will skip a moment, where you need to register your projects to yourself. Basicly, guys that manage CocoaPods have created a web service, that knows, which computer has permissions to which Pod.

    But when you have done this, you have to know, how to publish new versions of your Pods. You have to create a tag and push it on a new version as before and use that tag in your pod spec file.

    $ git tag -a 1.0.2 -m '1.0.2'
    $ git push --tags
    

    Then you should check your new updated pod spec.

    pod spec lint
    

    Then you just push your pod spec to a web service. Now you do not have to create one more folder for a new PodSpec file, copy it to your Specs fork and create a pull request. Everything is much simpler!

    $ pod trunk push ./DKProgressHUD.podspec
    

    Here it is important to tell a path to your pod spec file. I use here a dot since my pod spec file is located in the folder, where I am currently in Terminal.
    For more information read a blog of CocoaPods project.

    If you are asked to register a session first, do this:

    $ pod trunk register name@example.org 'Your Name' --description='macbook pro'
    

    In my case:

    $ pod trunk register alwawee@gmail.com 'Dennis Kutlubaev' --description='iMac at the office'
    
  • New cool custom Activity Indicator for iOS

    Recently I have created a new open-source project of an activity indicator for iOS, called DKProgressHUD.

    Today I merged a contribution from Edan Lichtenstein, which significantly improves it. This is how it looks now on iPhone:

    DKProgressHUD

    DKProgressHUD on GitHub

    Available via Cocoapods:

    pod DKProgressHUD