Tuesday, February 23, 2016

ios Embedded UITabBarController in UINavigationViewController

When designing ios App in storyboard, certain UITabBarController cannot be embedded into UINavigationviewController in the same way as other view controller.

One approach to solve the issue it just adding a regular UIViewController into the storyboard and embedded it into navigation view controller. And then add a view of TabBar into the UIViewController. With this approach, you will need to set the tabbar UIView's delegate by yourself.

Another approach is still using UITabBarController and then open the tabbarcontroller using show method from a segue. With this way, you get the full function provided by UITabBarController, but you cannot set the UINavigationBar's title and bar button from storyboard. Instead you will need to set them from the viewdidLoad() method as shown below.

  override func viewDidLoad() {
        super.viewDidLoad()
        
        self.navigationItem.title = "Settings"
        
        let leftButton : UIBarButtonItem = UIBarButtonItem(title: "Save", style: UIBarButtonItemStyle.Plain, target: self, action:"save:");
        leftButton.tintColor = UIColor.whiteColor()
        self.navigationItem.leftBarButtonItem = leftButton
        
        let rightButton : UIBarButtonItem = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Plain, target: self, action:"cancel:");
        rightButton.tintColor = UIColor.whiteColor()
        self.navigationItem.rightBarButtonItem = rightButton

    }
    

    func cancel(sender: UIBarButtonItem) {
        print("cancel clicked")
         self.performSegueWithIdentifier("returnToParent", sender: self)
        
    }
    
    func save(sender: UIBarButtonItem) {
        print("save clicked")
        
        self.performSegueWithIdentifier("saveAndReturnToParentt", sender: self)
    }
     
Option 2 seems better as most of the code required for the function is within the viewDidLoad method.

Sunday, February 21, 2016

Unique swift syntax

 1. Nil Coalescing Operator:  a??b  
The nil coalescing operator (a ?? b) unwraps an optional a if it contains a value, or returns a default value b if a is nil. The expression a is always of an optional type. The expression b must match the type that is stored inside a.

a??b
is shorthand for the code below:
a != nil ? a! : b

2. Inclusive Range Operator: for i in a...b {} 

The closed range operator (a...b) defines a range that runs from a to b, and includes the values a and b. The value of a must not be greater than b.

for index in 1...5 {
    print("\(index) times 5 is \(index * 5)")
}

3. Half-Open Range Operator:  for i in a..<b {} 

The half-open range operator (a..<b) defines a range that runs from a to b, but does not include b. It is said to be half-open because it contains its first value, but not its final value.
for index in 1..<5 {
    print("\(index) times 5 is \(index * 5)")
}

4. Stride
The stride provides steps to loop through a range, either including the last value (through) or excluding the last value
for num in stride(from: 1000, through: 0, by: -100)  {
    print(num)

}

5. Argument and Parameter names for  function
In a method declaration, if the argument (external name) is specified, then when calling the method, the caller must specify the argument name. In order to skip the argument name, set the name to _ in function definition.

func someFunction(_ firstParameterName: Int, _ secondParameterName: Int)  {
    // function body goes here
    // firstParameterName and secondParameterName refer to
    // the argument values for the first and second parameters
}
someFunction(1, 2)

6. Parameter name for Closure
When defining closure variable, only parameter type information is specified, the argument names are skipped as the proper parameter names should be decided by the particular closure or function implementation, and the names are specified when defining the closure implementation body as shown below

    var handlerWithParamAndValue : (Int, String) -> String  =  {pi, ps in
        return pi.description + " " + ps
    }


let k = handlerWithParamAndValue(1, "yes")
print("the value is \(k)") 

7: try, try?, try! expression
try before an expression indicates the expression may throw exception.

try? before an expression indicates the expression returns an optional value. And if an error is thrown while evaluating the expression, the optional value is set to nil, and the error is eaten silently

try! before the expression indicates even if theoretically the expression may throw an error, but in this particular call, it will never throw an error.

8. In for in loop, add a where clause to only loop through the items that match certain condition, for example
for data in numbers where data % 2 == 0 {
    print(data)
}

This follows the same syntax as extension definition
extension Array where Element : Equable {
...
}

Friday, February 19, 2016

iOS shows alert view independent of current viewcontroller

Usually when displaying alert view on ios, it is presented by the current topmost viewcontroller. However, sometime, the current topmost presented viewcontroller may not be easy to get , or the current presented viewcontroller may get dismissed while the new alertview is displayed.

To handle the issue, one option is create a new UIWindow object and make it visible, then create a empty root viewcontroller for the UIWindow. Then show the alert view on top of the new UIWindow's root viewcontroller. This approach can show the uialert view regardless which viewcontroller is currently shown by other part of application logic.

The sample code is shown below:
        __block UIWindow* win= [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        win.rootViewController = [[UIViewController alloc] init];
        win.windowLevel = UIWindowLevelAlert + 1;
        [win makeKeyAndVisible];
        UIAlertController* alert = [UIAlertController
                                    alertControllerWithTitle:@"Change Password"
                                    message:@"The password has been updated, click OK to reload the page."
                                    preferredStyle:UIAlertControllerStyleAlert];
        
        UIAlertAction* defaultAction = [UIAlertAction
                                        actionWithTitle:@"OK" style:UIAlertActionStyleDefault
                                        handler:^(UIAlertAction * action) {
                                            [self reloadStartUrl];
                                            win.rootViewController = nil;
                                            win.hidden = true;
                                            win = nil;

                                        }];
        
        [alert addAction:defaultAction];

        [win.rootViewController presentViewController:alert animated:YES completion:nil];
        

Thursday, February 4, 2016

Using ios storyboard constraint for view (wkwebview) object created at runtime

ios xcode storyboard provides easy way to control the view object's layout by constraints. But the constraints only work in interface builder with design time UIView object. If you need to create UIView object at runtime, such as wkwebview, then the constraint will not help.

One option is defining a simple UIView object at design time in storyboard as place holder, this UIView object can be used to define all the required constraint in interface builder. And then at runtime, after the wkwebview or any other view object is created, just add the new view object as the subview in the place holder UIView object, and also set the new view object's autoresizingmask to let it automatically change its size based on the place holder's size and location.

- (void)viewDidLoad {
    [super viewDidLoad];
     WKWebViewConfiguration *theConfiguration =
    [[WKWebViewConfiguration alloc] init];
    theConfiguration.preferences.javaScriptEnabled = true;
    
    CGRect rect = CGRectMake(0, 0, self.containerView.frame.size.width, self.containerView.frame.size.height);
    self.theWebView = [[WKWebView alloc] initWithFrame: rect configuration: theConfiguration];
    self.theWebView.navigationDelegate = self;
    
    self.theWebView.autoresizingMask =
    //   UIViewAutoresizingFlexibleLeftMargin|
    //   UIViewAutoresizingFlexibleBottomMargin ;
    //   UIViewAutoresizingFlexibleRightMargin |
    //   UIViewAutoresizingFlexibleTopMargin  |
        UIViewAutoresizingFlexibleHeight    |
        UIViewAutoresizingFlexibleWidth;
    
    
    [self.containerView addSubview:self.theWebView];

}

Wednesday, February 3, 2016

ASP.NET MVC identity provider authentication timeout

When using .net identity authentication, the authentication timeout settings is set by code in Startup.Auth.cs, the cookieAuthenticationOptions can set ExpireTimeSpan to decide when the user log in session will be expired,
      app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    // Enables the application to validate the security stamp when the user logs in.
                    // This is a security feature which is used when you change a password or add an external login to your account.
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(20),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                },
                ExpireTimeSpan = TimeSpan.FromMinutes(60*2),

            });

Setting the session timeout in web.config sessionstate or iis application session timeout setting does not affect the .net identity authentication timeout.

In addition, this timeout is not set into cookie expiration property. Instead it is managed on server side

This applies to both local database identity provider or third party identity provider, like google oauth2