Monday, May 29, 2017

A great video I found

https://www.youtube.com/watch?v=9wS04HLsCzo&t=1143s

It answers quite a few questions bothering me.  Great video!

Tuesday, February 21, 2017

在程序被送入后台时,向 iOS 借点时间,来完成一个长期任务

was fixing a 0x000000008badf00d "crash" and found this to read.


转载自 http://www.cnblogs.com/lyanet/archive/2013/03/26/2983079.html by _安静ゝ

12.2.2. 方案 
使用UIApplicationbeginBackgroundTaskWithExpirationHandler: 实例方法。在你完成任务后,调用UIApplicationendBackgroundTask:方法。 
12.2.3. 讨论 
当一个iOS应用被送到后台,它的主线程会被暂停。你用NSThreaddetachNewThreadSelector:toTar get:withObject:类方法创建的线程也被挂起了。如果你想在后台完成一个长期任务,就必须调用UIApplicationbeginBackgroundTaskWithExpirationHandler:实例方法,来向iOS借点时间。UIApplicationbackgroundTimeRemaining属性包含了程序完成他的任务可以使用的秒数。如果在这个期限内,长期任务没有被完成,iOS将终止程序。每个对beginBackgroundTaskWithExpirationHandler:方法的调用,必须要相应的调用endBackgroundTask:方法(UIApplication的另一个实例方法)。也就是说,如果你向iOS要更多时间来完成一个任务,你必须告诉iOS你什么时候能完成那个任务,那时,你的程序将iOS 5 Programming Cookbook www.devdiv.com 翻译整理 
DevDiv 翻译:kyelup cloudhsu 耐心摩卡 wangli2003j3 xiebaochun dymx101 jimmylianf BeyondVincent 20 DevDiv 校对:laigb kyelup DevDiv 编辑:BeyondVincent 版本 1.0 | 2012  07  30 日 

和其所有被暂停的线程被放入后台。 
当你的程序在前台时,UIApplicationbackgroundTimeRemaining属性等于DBL_MAX常量,这是double类型可表示的最大值(和这个值相当的integer通常等于-1)。在iOS被要求在程序被完全挂起之前给于更多的执行时间,这个属性指明了在完成任务前程序拥有多少秒。 
在程序中你可以多次调用beginBackgroundTaskWithExpirationHandler:方法。要记住的重点是,当iOS为你的程序返回一个token或者任务标识(task identifier)时,你都必须调用endBackgroundTask:方法,在运行的任务结束时,用来标志任务结束。如果你不这么做的话,iOS会终止你的程序。 
在后台时,程序不应该执行完全的功能,也不应该处理大量数据。事实上,他们只应该完成一个长期任务。 
比如,一个程序正在调用一个web service API,并且还没有从服务器上的那个API接收到响应。在此期间,如果程序被送入后台,它可以请求更多的时间,直到它从服务器收到响应。一旦响应被接收,程序必须保存其状态,并调用UIApplicationendBackgroundTask:实例方法将任务标记为完成。 
让我们看一个例子。我将从在应用程序委托中定义一个UIBackgroundTaskIdentifier类型的属性开始。同时,让我们定义一个NSTimer,当程序被送到后台时,我们将用它每隔1秒向控制台窗口输出一条消息: 
#import <UIKit/UIKit.h> 
@interface Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate : UIResponder <UIApplicationDelegate> 
@property (nonatomic, strong) UIWindow *window; 
@property (nonatomic, unsafe_unretained) UIBackgroundTaskIdentifier backgroundTaskIdentifier; 
@property (nonatomic, strong) NSTimer *myTimer; 
@end 
接下来我们继续同步属性: 
#import "Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate.h" @implementation Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate 
@synthesize window = _window; 
@synthesize backgroundTaskIdentifier; @synthesize myTimer; 
现在,让我们创建定时器,并在程序被送到后台时启动它: 
- (BOOL) isMultitaskingSupported{ 
BOOL result = NO; 
if ([[UIDevice currentDevice] 
respondsToSelector:@selector(isMultitaskingSupported)]){ result = [[UIDevice currentDevice] isMultitaskingSupported]; 
return result; 
- (void) timerMethod:(NSTimer *)paramSender{ 
NSTimeInterval backgroundTimeRemaining = 
[[UIApplication sharedApplication] backgroundTimeRemaining]; 
if (backgroundTimeRemaining == DBL_MAX){ NSLog(@"Background Time Remaining = Undetermined"); 
} else { iOS 5 Programming Cookbook www.devdiv.com 翻译整理 
DevDiv 翻译:kyelup cloudhsu 耐心摩卡 wangli2003j3 xiebaochun dymx101 jimmylianf BeyondVincent 21 DevDiv 校对:laigb kyelup DevDiv 编辑:BeyondVincent 版本 1.0 | 2012  07  30 日 

NSLog(@"Background Time Remaining = %.02f Seconds", 
backgroundTimeRemaining); 
} } 
- (void)applicationDidEnterBackground:(UIApplication *)application{ 
if ([self isMultitaskingSupported] == NO){ 
return; } 
self.myTimer = 
[NSTimer scheduledTimerWithTimeInterval:1.0f 
target:self 
selector:@selector(timerMethod:) userInfo:nil 
repeats:YES]; 
self.backgroundTaskIdentifier = 
[application beginBackgroundTaskWithExpirationHandler:^(void) { [self endBackgroundTask]; 
}]; } 
你可以看到,在后台任务的完成处理者(completion handler)中,我们调用了应用程序委托的endBackgroundTask方法。这是一个我们编写的方法,如下: 
- (void) endBackgroundTask{ 
dispatch_queue_t mainQueue = dispatch_get_main_queue(); 
__weak Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate *weakSelf = self; 
dispatch_async(mainQueue, ^(void) { 
Completing_a_Long_Running_Task_in_the_BackgroundAppDelegate *strongSelf = weakSelf; 
if (strongSelf != nil){ 
[strongSelf.myTimer invalidate]; 
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskIdentifier]; 
strongSelf.backgroundTaskIdentifier = UIBackgroundTaskInvalid; } 
}); } 
在长期任务结束后,我们需要做一些事情进行清理: 
1. 结束所有的线程和定时器,不管他们是基础定时器还是GCD中创建的。 
2.调用UIApplicationendBackgroundTask:方法来结束后台任务。 
3.将任务标识设置为UIBackgroundTaskInvalid,标志我们的任务结束。 
最后,当我们的应用回到前台,如果我们的后台任务还在执行中,我们需要确保我们在干掉它: 
- (void)applicationWillEnterForeground:(UIApplication *)application{ 
if (self.backgroundTaskIdentifier != UIBackgroundTaskInvalid){ 
[self endBackgroundTask]; } 
在我们的例子中,不论何时程序被送到后台,我们都会要求更多时间以完成一个长期任务(例如,在这里是我们计时器的代码)。在我们的时间里,我们不断的读取UIApplication实例中backgroundTimeRemaining属性的值,将它打印到控制台。在UIApplicationbeginBackgroundTask WithExpirationHandler: 实例方法中,在程序的额外时间内完成一个长期任务之前,我们提供的代码将被执行(一版大概在任务过期前510秒)。在此,我们只要调用UIApplicationendBackgroundTask:实例方法来结束任务。

Wednesday, November 9, 2016

How to use barrier

Example:
https://github.com/lingzt/BarrierPra
By using the barrier, I can make sure every time getter starting after the previous setter finished.


#import "ViewController.h"

NSString *_name;
@interface ViewController ()
@property (nonatomic, strong, readwrite) NSString *name;@property (nonnull, strong, nonatomic) dispatch_queue_t syncQueue;@end
@implementation ViewController- (void)viewDidLoad {

    [super viewDidLoad];    //并行队列   set up on global queue    _syncQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    for(int i=0; i<1000; i++){
        NSString *tempName = [NSString stringWithFormat:@"%d",i];        [self name];        [self setName:tempName];
    }

}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}




//用同步  sync with global queue- (NSString *)name{
    __block NSString *localName;    dispatch_sync(_syncQueue, ^{
        localName =_name;        NSLog(@"getter");        NSLog(localName);    });    return localName;}
//利用异步栅栏块  async with global que, with barrier- (void)setName:(NSString *)name{
    dispatch_barrier_async(_syncQueue, ^{
        _name = name;        NSLog(@"settter");        NSLog(_name);    });}


@end

Monday, November 7, 2016

Effective Objective-C 2.0 study notes

in Chinese, great stuff!
http://www.cnblogs.com/purple-sweet-pottoes/p/4742552.html

http://blog.csdn.net/sanjunsheng/article/details/44371341

difference bw category & extension

Category:
1. The category .h file is optional. When it is deleted the .m file have to import the main .h file
2.  To expose the method, it has to be declared in the .h file.
3. Can't declare any new property in the category.

Extension:
1. Kinda like category,  but anonymous, what is even better,  it can declare the new property!
2. Can be used to expose read-only properties.
for example:

in main .m file, declare the internal method

@interface Account ()

@property (nonatomic, readonly) NSString* randomStuff;
+ (void)setCurrentAccount:(Account*)account;

then implement the method
+ (void)setCurrentAccount:(Account*)account
{
    currentAccount = account;}


in other class's .m file, set extension interface to expose the method to the current class.


@interface Account ()
+ (void)setCurrentAccount:(Account*)account;@end

later in this class, we will be able to call the private method.

- (void)cleanCurrentUser{
    [Account setCurrentAccount:nil];
}

Sunday, November 6, 2016

ReactiveCocoa

I have found some senior people heavily using ReactiveCocoa in the project I am currently working on. So, knowing ReactiveCocoa https://github.com/ReactiveCocoa/ReactiveCocoa is my homework of this Sunday.

Following are some material I am following today:







Study note:
It is 1:30am and I really got to go to bed. That way I will have enough energy for pairing with others tomorrow.

It was not as productive as I expected, so so far I found RAC has something to do with MVVM, which is super cool.
More reading to come: https://www.objc.io/issues/13-architecture/mvvm/