Monday, December 17, 2018

Avoid repeated prompt for username and password to allow keychain access on mac

Quite often Mac asks user to give permission for certain operations so the application is can access keychain items. Sometimes even if user inputs the right user name and password, user is still not able to finish the operation. The following steps can be used to avoid this

For client certificate keychain item:
1. Identify which keychain item is used by the operation,
2. open keychain app and select and right click the item, select Get Info menu item
3. open trust section, change "Use System Default" to "Always Trust"
4. save the change



For password keychain item
1. Identify which keychain item is used by the operation,
2. open keychain app and select and right click the item, select Access Control tab
3. select "allow all applications to access the item"
4. save the change



Tuesday, December 11, 2018

iOS viewcontroller completion block and retain cycle

It is well known that when referring self or instance variable inside a block, it is better to use
a __weak reference variable to avoid memory leak due to retain cycle. But this may not be necessary in all the cases, and sometimes it is better to use self instead a weak self reference.

First let see a case how retain cycle happens.
@interface RetainCycle : NSObject{
    void (^testBlock)(void);
}

@property (strong) NSString* mystr;
-(void)setup;

@end

@implementation RetainCycle
-(void)dealloc{
    NSLog(@"RetainCycle instance: %@ deallocated", self);
}

-(id)init {
    NSLog(@"Init called %@", self);
    return self;
}

-(void)setup{
    testBlock= ^{
        self.mystr = @"hi";
        NSLog(@"Integer is: %@", self.mystr);
    };
}
@end

For the above RetainCycle interface, if an app calls the below method
-(void) test {
    RetainCycle* rc = [[RetainCycle alloc] init];
    NSLog(@"RetainCycle obj: %@ created", rc);
    [rc setup];
}
then after the method returns, the RetainCycle instance will not be released. The reason is self is retained within the testBlock due to reference to self.mystr, and testBlock is retained as a property of RetainCycle.

The means retain cycle only happens, if the block is keeping retained by self or its property.

If we change the above code to the below line, then the retain cycle related memory leak will not happen

    __weak void (^testBlock)(void);



Now, we can look another popular case, where retain cycle does not happen, that is the completion block used by view controller.

@interface TestViewController : UIViewController


@end

@implementation TestViewController

-(void)dealloc{
    NSLog(@"*******TestViewController instance: %@ deallocated", self);
}


- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
}

- (IBAction)onDismiss:(id)sender {
    [self.presentingViewController dismissViewControllerAnimated:YES completion:^{
        NSLog(@"Test View controller dismissed %@", self);
    }];
}
@end

In this case, after creating and showing the viewcontroller, user can click the dismiss button to dismiss the view controller. Notice the dismissViewController method's completion block also refers self for NSLog output, but it would not cause memory leak due to retain cycle.

The reason is although the block retains the self for writing NSLog data. But self (viewController) only temporarily retain the block. After the viewController is dismissed, the completion block returned by view controller will be released, and so block will deallocate itself and all objects retained by itself.  So there is no need to change self to a weak reference in the completion block used by view controller. This is also indicated by the xcode debugger, which will call _Block_release after the view controller is dismissed

Actually in most case, we may want to use strong self for view controller completion block, as the operation will need the view controller alive to finish, such as read the text input from the view controller's text field.