Objective C study note

Redirect your app to the System Settings App

When use some functionality related to user’s privacy, say CoreLocation Framework, there would always be a problem that user may deny the app request for their current location and the app cannot work correctly. There is nothing we can make decision for the user, but at least we can help them enable that service easier.

That is the topic today — redirection to the Settings App

There are two types of redirection you want to make: redirect to the ①App Specific Settings Page and ②System Settings Page


①Redirect to App Specific Settings Page

Prior to iOS 8, there is no way to do that. So if you want to back support to iOS 7 , make sure to check the availability

NSURL *url = [NSURL URLWithString: UIApplicationOpenSettingsURLString];
if([UIApplication sharedApplication] canOpenURL: url){
        [[UIApplication sharedApplication] openURL:url];
}

Notice that url is actually the @”app settings”, which would directly get you into the page that user can enable the location request


②Redirect to System Settings

Here is the goal we want to achieve. Before user can accept your app’s request for the location service, user may globally disable the location preference, and your app cannot even trigger that request. So we need to do some additional work to make it happen.

First, go the your App’s Target, under Info, there is a section for URL Types.
URL Type Settings

Add this one which just put URL Schemes called “prefs”

Then inside your code, when you want, call (e.g I want to go to the location under privacy on Settings)

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=Privacy&path=LOCATION"]];

And that’s it!

This method should be okay to use after iOS5.1, I tested on iOS8.4 and iOS 9 it works great! Any feed back is very appreciated!

Journey to App Store

Take PERFECT screenshots before submit your App to the App Store

Before you release you app to the world, you would definitely want to show the fancy of your app by screenshots. Although you can easily make screenshots in the simulator or on your phone, the status bar has always been a pain:

  • Time, time, time
  • I don’t want to show the poor signal of my “T-Maybe”
  • Wait my battery is gonna run off?

In this blog, I will take about how to make a perfect screenshot just like Apple.


1. Smart use of Quicktime

In iOS8, thanks to Apple, it is relatively easy to do a live demo on the phone with the cool feature from quicktime. However, as you may never noticed, when you connect your phone to your laptop and open the quick time for the demo, your status bar would automatically switched to the present mode! Will full signal, no carrier name and full battery! And of course, it would display the Apple’s standard demo time: 9:41AM!Untitled-1
Now grab your phone and take a screenshot!


2. Take screenshot on the simulator

If you prefer to do the screenshot on the simulator and do not want the ugly “Carrier” or the real time, we have another option

SimulatorStatusMagic(https://github.com/shinydevelopment/SimulatorStatusMagic) provide you a very simple way to do that. Just go ahead and clone that repo, build that on the simulator you want(iPhone 6, iPhone 5s etc), and hit the only button!iOS Simulator Screen Shot Jul 20, 2015, 2.55.46 PMiOS Simulator Screen Shot Jul 20, 2015, 2.56.33 PM

The simulator retain this status bar and now you could go into your app and user Command+S to make screen shots!


What is next…

After get your perfect screenshot, try the Screenshot Builder on LaunchKit and happy App Store 😀

Objective C study note

Apply CSS into your UIWebVIew

First, you need to drag your .css file into your Xcode workspace, I dragged it into the “Supporting Files/”

Then, all you need is these three lines:

NSString *path = [[NSBundle mainBundle] resourcePath];
NSURL *baseURL = [NSURL fileURLWithPath:path];
[webView loadHTMLString:htmlString baseURL:baseURL];

If you’re curious, you can actually log out everything you have in the resourcePath of your App.

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSArray *dirContents = [fileManager contentsOfDirectoryAtPath:path error:nil];
    NSLog(@"Contents = %@",dirContents);

If you can see your *.css file, you are good to go!

Of course, you would need to add a line of CSS code into the header of your html string to make it aware of that CSS file.

NSMutableString *finalHtmlString = [[NSMutableString alloc]initWithString:@"<link href=\"mobile.css\" rel=\"stylesheet\" type=\"text/css\">"];
[finalHtmlString appendString:htmlString];

BeforeAfter
Before                                                                 After

Uncategorized

Useful Plugins for Xcode

Xcode is the best IDE for development I’ve ever used. But with the plugins I suggest below, it would become even better.


Alcatraz

Before reading anything below, make sure you have this tool installed. It would save you tons of time for searching and installing plugins in Xcode.


1. Backlight

Backlight is a tool that can highlight the current editing line in Xcode. It would be a life saver when you have more than 100 lines of code and suddenly you find you need to import another head file and come back to your current working line.

screenshot


2. FuzzyAutocomplete

At the first time when I see this plugin, I hesitated. I had a fear that if I use this plug in too much, I would not be able to remember any name of the methods. But when I tried it, I just cannot let it go. This is a wonderful exploring tool. Thanks to auto complete, we can guess for the name of the methods instead of looking it up in the Apple’s Documentation.  You will feel its power:)


3.  VVDocumenter-Xcode

68747470733a2f2f7261772e6769746875622e636f6d2f6f6e65766361742f5656446f63756d656e7465722d58636f64652f6d61737465722f53637265656e53686f742e676966

This is a nice documentation tool for others to understand your code better! You can easily triggered it by type “///“, it will automatically create a template with all the parameters and the return value in your method.


4. GitDiff

The GitDiff is a wonderful tool for ‘Git’ guys. It can keep track of what has been changed compared to the latest git commit, using different color of line aside the line number(Orange for modified line and blue for the added line).

687474703a2f2f696e6a656374696f6e666f7278636f64652e6a6f686e686f6c6473776f7274682e636f6d2f67697464696666322e706e67


5. KSImageNamed

The function of this plugin is simple but very useful. It integrate the auto-complete for the images you use in your project. The auto-complete makes the life a lot easier isn’t it?


There are many more plugins in the Alcatraz, explore it! And if you found a great one, please share with me 🙂

Objective C study note

Deep Copy and Shallow Copy in Objective C

I would like to share with you guys this topic which has bothered me so many times before and we all should pay special attention to.

Let’s do an experiment first.

I would create a Class called Person, set 2 properties as “Name” and “Age”.

#import <Foundation/Foundation.h>

@interface Person : NSObject
@property(strong,nonatomic)NSString *name;
@property(nonatomic)NSUInteger age;
-(instancetype)initWithName:(NSString *)name Age:(NSUInteger)age;
@end

Then in the main file, I create three reference of person.

Person *personA = [[Person alloc]initWithName:@"Cong Sun" Age:24];
Person *personB = personA;
Person *personC = personA;

Then if I changed the age of the personA, guess what happened? All of the ‘age’ property for those three people has changed!  Let’s look into the memory to see what exactly happened

Screen Shot 2015-06-07 at 6.05.52 PM

Here, we can see that all the three person’s memory address are identical, which we say that personB and personC are the Shallow Copy of personA. They are all the pointers pointing to the same memory address. So we can treat them as personA’s alias.  When you use personB = personA, you are not passing all the properties of the personA to the personB, but pass the point to it.

The Deep Copy, on the contrary,  is the copy of the object’s value. After deep copy, any manipulate to the object will not affect its copy. Let’s take the NSMutableArray as a simple example.(At the beginning the reason we use the Person Class is because the Array class won’t show the actual memory address on the debug console)

NSMutableArray *array1 = [[NSMutableArray alloc]init];
NSMutableArray *shallowCopy = array1;
[array1 addObject:@1];
NSMutableArray *deepCopy = [[NSMutableArray alloc]initWithArray:array1];
[array1 addObject:@2];

and let’s pull out what happened on the memory

Screen Shot 2015-06-07 at 6.21.10 PM

The Objective C gives us a good tool to get a deep copy using its in-built initializer. We can figure out right here in the memory, the deep copy of the array1 will not add the @2 into the array however the shallow copy, which shares the same memory address will be modified as we manipulate the array1.

So how can we avoid the shallow copy mistake when necessary? I would say using ‘alloc’. The ‘alloc’ will create a new memory space for the variable and make it point to that address. Then, if the OC has that initializer to perform the deep copy, do it, otherwise, we need to copy every single property of the object to the new object. For example, we can do the deep copy for the Person class like this:

Person *personA = [[Person alloc]initWithName:@"Cong Sun" Age:24];
Person *personB = personA;
Person *deepCopyPerson = [[Person alloc]init];
//deep copy
deepCopyPerson.name = personA.name;
deepCopyPerson.age = personA.age;

personA.age = 26;

Screen Shot 2015-06-07 at 6.33.24 PM

Here we go, we can see the difference. The deepCopyPerson is not changed!

Now, see this example, we can load the memory address by using %p

        NSString *a = @"abc";
        NSString *b = a;
        NSLog(@"memory location of a = %p",a);
        NSLog(@"memory location of b = %p",b);
        a = @"def";
        NSLog(@"memory location of modified a %p",a);

The NSString is also a pointer pointing to a specific memory address. So What would happen to NSString b?

Screen Shot 2015-06-09 at 1.11.47 PM

At the first step, when we assign b = a, we can see they point to the same memory address. So b is a shallow copy of a. However, when we modify the value of a, we got this result

Screen Shot 2015-06-09 at 1.17.44 PM

The b stays the same value! This is tricky but when we see the console, we can get the reason:

Screen Shot 2015-06-09 at 1.16.27 PM

When we do a = @”def”, we are doing the same thing as

a = [[NSString alloc]initWithString:@”def”];

Which will make a point to another memory address. However the b still hold the previous memory address of a, so even it is a shallow copy, it doesn’t matter. The trick is, only the modification on the value stored in the specific memory address the pointer points to will have the effect on all of the pointers’ shallow copies 🙂

Tips:

Class like NSMutableArray has the initializer like initWithArray can make the deep copy directly! Try to dig into the documentation and be lazy when you can!

The OC’s NSCopying protocol is essentially doing a deep copy. In the situation when you want to use the NSDictionary, the key has to follow the NSCopying protocol to make a deep copy into the dictionary so that it wouldn’t be changed in the future. You can view this blog for more information http://bynomial.com/blog/?p=73