miércoles, 27 de enero de 2016

iOS: Singleton

Objective C

+ (SafeStorage*)sharedInstance
{
    static SafeStorage *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

Swift

class Server {
   
    static let sharedInstance = Server()
   
    private init() {
       
    }

}

iOS: Semaphore, Locks, Multithreading

Semaphore

static dispatch_semaphore_t newAgent;

newAgent = dispatch_semaphore_create(0);

dispatch_semaphore_signal(newAgent);

dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kWaitForNewAgents * NSEC_PER_SEC));

dispatch_semaphore_wait(newAgent, timeout);


dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

Lock

static NSLock *agentLock;

agentLock = [[NSLock alloc]init];

[agentLock lock];

[agentLock unlock];


dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});

Create own queue:

dispatch_queue_t myQueue = dispatch_queue_create("My Queue",NULL);

dispatch_async(myQueue, ^{
    // Perform long running process
   
    dispatch_async(dispatch_get_main_queue(), ^{
        // Update the UI
       
    });
});

Groups

dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block1
    NSLog(@"Block1");
    [NSThread sleepForTimeInterval:5.0];
    NSLog(@"Block1 End");
});


dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^ {
    // block2
    NSLog(@"Block2");
    [NSThread sleepForTimeInterval:8.0];
    NSLog(@"Block2 End");
});

dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0*), ^ {
    // block3
    NSLog(@"Block3");
});

Common usage

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0*), ^(void){
    //Background Thread
    dispatch_async(dispatch_get_main_queue(), ^(void){
        //Run UI Updates
    });

});

*Can be either 0 (or NULL), DISPATCH_QUEUE_CONCURRENT or DISPATCH_QUEUE_SERIAL.

martes, 26 de enero de 2016

iOS: AlertView deprecated

UIAlertController * alert=   [UIAlertController
                                  alertControllerWithTitle:@"Title"
                                  message:@"Message"
                                  preferredStyle:UIAlertControllerStyleAlert];
    
    UIAlertAction* yesButton = [UIAlertAction
                                actionWithTitle:@"Yes, please"
                                style:UIAlertActionStyleDefault
                                handler:^(UIAlertAction * action)
                                {
                                }];
    UIAlertAction* noButton = [UIAlertAction
                               actionWithTitle:@"No, thanks"
                               style:UIAlertActionStyleDefault
                               handler:^(UIAlertAction * action)
                               {
                               }];
    
    [alert addAction:yesButton];
    [alert addAction:noButton];
    

    [self presentViewController:alert animated:YES completion:nil];

iOS: Dispatch on main thread

Objective C

dispatch_async(dispatch_get_main_queue(), ^(){
    //Do something
});

Swift

DispatchQueue.main.asyncAfter(deadline: .now() + 1.0, execute: {
    ...
})

iOS: Global constant in Xcode

Project Navigator > Select your project > Build Settings > Apple LLVM 7.0 - Preprocessing > Preprocesor Macros > Click on "debug" or "release" and add the desired value(s)

lunes, 25 de enero de 2016

iOS: LocalNotification

NSDate* date = [[NSDate date] dateByAddingTimeInterval:10];
    
    UILocalNotification *localNotification = [[UILocalNotification alloc] init];
    localNotification.fireDate = date;
    localNotification.alertBody = [NSString stringWithFormat:@"Alert Fired at %@", date];
    localNotification.soundName = UILocalNotificationDefaultSoundName;
    localNotification.applicationIconBadgeNumber = 1;

    [[UIApplication sharedApplication] scheduleLocalNotification:localNotification];

viernes, 22 de enero de 2016

iOS: NSNotificationCenter

Receiver


- (void)viewDidDisappear:(BOOL)animated
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    [super viewDidDisappear: animated];
}


- (void)viewWillAppear:(BOOL)animated
{

    [super viewWillAppear: animated];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveNotification:) name:@"Notification" object:nil];
}

- (void) receiveNotification:(NSNotification *) notification
{
    // Do something
}

Somewhere in another class

[[NSNotificationCenter defaultCenter] postNotificationName:@"Notification" object:self];

martes, 19 de enero de 2016

iOS: Blocks

Property

@property (copy) void (^blockProperty)(void);

Method definition

- (void)beginTaskWithName:(NSString *)name completion:(void(^)(void))callback;

Inline implementation

[array enumerateObjectsUsingBlock:^ (id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"Object at index %lu is %@", idx, obj);
    }];

If you need to be able to change the value of a captured variable from within a block, you can use the __block storage type modifier on the original variable declaration.

__block int anInteger = 42;


iOS: Watch

Watch

iOS: Registering for remote notifications


- (void)applicationDidFinishLaunching:(UIApplication *)app {
   // other setup tasks here....
 
   // Register the supported interaction types.
    UIUserNotificationType types = UIUserNotificationTypeBadge |
                 UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
    UIUserNotificationSettings *mySettings =
                [UIUserNotificationSettings settingsForTypes:types categories:nil];
    [[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];
 
   // Register for remote notifications.
    [[UIApplication sharedApplication] registerForRemoteNotifications];
}
 
// Handle remote notification registration.
- (void)application:(UIApplication *)app
        didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
    const void *devTokenBytes = [devToken bytes];
    self.registered = YES;
    [self sendProviderDeviceToken:devTokenBytes]; // custom method
}
 
- (void)application:(UIApplication *)app
        didFailToRegisterForRemoteNotificationsWithError:(NSError *)err {
    NSLog(@"Error in registration. Error: %@", err);
}
Note: 
1) If a cellular or Wi-Fi connection is not available, neither the  "application:didRegisterForRemoteNotificationsWithDeviceToken:" method nor the "application:didFailToRegisterForRemoteNotificationsWithError:" method is called.
2) Never cache a device token; always get the token from the system whenever you need it. If your app previously registered for remote notifications, calling the registerForRemoteNotifications method again does not incur any additional overhead, and iOS returns the existing device token to your app delegate immediately.
3) In addition, iOS calls your delegate method any time the device token changes, not just in response to your app registering or re-registering.

jueves, 14 de enero de 2016

iOS: Add a view on top of every view


[[[UIApplication sharedApplication] keyWindow] addSubview:myView];

iOS: Editable UITableView

@interface ViewController ()

@property(nonatomic, retain) UIBarButtonItem* addButton;

@end

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    self.navigationItem.rightBarButtonItem = self.editButtonItem;
    
    _addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addItem:)];
    self.navigationItem.leftBarButtonItem = _addButton;

}

#pragma mark - UITableViewDelegate

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
    [super setEditing:editing animated:animated];
    
    [self.tableview setEditing:editing animated:YES];
    
    if (editing) {
        _addButton.enabled = NO;
    } else {
        _addButton.enabled = YES;
    }
}

- (UITableViewCellEditingStyle)tableView:(UITableView*)tableView editingStyleForRowAtIndexPath:(NSIndexPath*)indexPath
{
//    if (indexPath.row == _list.count - 1) {
//        return UITableViewCellEditingStyleInsert;
//    } else {
//        return UITableViewCellEditingStyleDelete;
//    }
    return UITableViewCellEditingStyleDelete;
}

- (void)addItem:(id)sender
{
    [self performSegueWithIdentifier:@"AddViewController" sender:self]; // Presents AddViewController modally
}

#pragma mark - Unwind segues
- (IBAction)dimiss:(UIStoryboardSegue*)segue
{
    
}

- (IBAction)doAddItem:(UIStoryboardSegue*)segue
{
    AddViewController* addViewController = segue.sourceViewController;
    NSString* provider = addViewController.provider.text;
    NSString* account = addViewController.account.text;
    NSString* password = addViewController.password.text;
    
    KeychainItemWrapper* item = [[KeychainItemWrapper alloc] initWithAccount:account service:provider accessGroup:nil];
    [item setObject:password forKey:@"v_Data"];
    
    self.list = [self getItemsFromKeychain];
    
    [self.tableview reloadData];
}

iOS: Expandable UITableView

@interface ViewController ()

@property(nonatomic, retain) NSIndexPath* selectedIndexPath;

@end

#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return _list.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSDictionary* item = [self.list objectAtIndex:indexPath.row];
    
    ExpandedTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ExpandedCell"];
   cell.clipsToBounds = YES;
   // Populate cell
        
    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    return self.selectedIndexPath != nil && self.selectedIndexPath.row == indexPath.row ? expanded_height : normal_height;

}

#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self.tableview beginUpdates];
        
    if (self.selectedIndexPath == nil) {
        self.selectedIndexPath = indexPath;
    } else {
        self.selectedIndexPath = nil;
    }

    [self.tableview endUpdates];
}