Text
Stored Property Observer in Swift
Firstly, let’s take a look at the following Code Example:
var str = "Hello, playground" { //"Hello, playground" willSet { print("willSet \(str) : \(newValue)") // "willSet Hello, playground : Hello, Antonio.\n" str = "Hi" print("willSet \(str) : \(newValue)") //"willSet Hi : Hello, Antonio.\n" } didSet { print("didSet \(str) : \(oldValue)") //"didSet Hello, Antonio. : Hello, playground\n" str = "Hi" print("willSet \(str) : \(newValue)") // //"didSet Hi : Hello, playground\n" } } str = "Hello, Antonio."
In Swift,
Stored Property has two function to notify observer when it will be set(trying but before it is set, willSet) and it has been set(trying and already set it, didSet). So, every time trying to set the property, the willSet function will be called first, followed by didSet.
Here I did an interesting experiment: trying to modify the property while these two observing functions are called.
In the willSet function, assign it to a new String “Hi” does not do anything. It looks like a temporary assignment, and then assign it back very soon, because in the next calling function didSet, str is “Hello, Antonio”, rather than “Hi”, also the oldValue was not changed either.
While, in the didSet function, assign it to a new String “Hi” does actually assign the String “Hi” to this property, it changed the property’s value indeed, though the oldValue is still “Hello, playground”.
This is because the willSet function is called before the Stored Property has actually been set, while the “didSet” function is called after the Stored Property has already been set. So, in willSet function, assign a new String will not change the property value, since it will be assigned soon, while in didSet function, the property has been assigned, there is no other assignment here, so if it’s assigned by a new String value, this property value will be changed.
There is one thing deserve to note, assign new value to the property in the willSet and didSet function will not invoke recursively willSet nor didSet observing function.
0 notes
Text
“Write Algorithms in Objective-C”- Merge Sort
This is part of series “Write Algorithms in Objective-C”.
Merge Sort is one of the most important Divide-and-Conque sorting algorithms in this world.
I have implemented in Objective-C, and published the code on gist, since github has better support for coding language syntax highlighting.
Several lessons I learned from implementing this algorithm in Obj-C, also I have listed them in my comment with the code. But I think they are so important and I’d like to listing them here as well:
Objective-C is just like C language, it pass-by-value instead of pass-by-reference, even pass a pointer address, it's still a value. You can't assign a new address to it.
[[NSMutableArray alloc] initWithCapacity:count]; would create an empty mutable array, which has nothing in it. You could either addObject: to it, or set the first unsigned index to an object.
E.g, If you just send the message "initWithCapacity:", it's an empty mutable array, you could addObject: which add the object to the array, and its index is 0. Or, you could just assign the 0th index with the object. You can't assign the object to other index at this moment. Like, you could not assign 1st index with object, otherwise, a runtime error will popup when you run it.
0 notes
Text
WWDC2014 Video 237 A Strategy for Great Work
This session is presented by Ken, who has more than 10 yrs experience working at Apple. Here are 10 Lessons he shared in this session.
Know a good idea when you see it
Don't try to solve every problem at once
Find smart friends and listen to them
Work should explain itself
Choose the simplest thing which might work
Only show your best work
Iterating quickly leads to better work
Be kind to people, but be honest about work
Separate yourself from your work
You’re never done
I specially present my affection on the following Lesson and Quote. Love this session.
0 notes
Text
Overview Structure with Core Data in iOS
In this article, I’ll present the entry level structure of Core Data used in iOS development. For detail programming guide on this topic, please follow this link. This article is mainly for my deep study reference only.
This image is “borrowed” from objc.io for education purpose. If any violation comes with it, the image will be removed.
This image perfectly explained the structure of Core Data in iOS.
NSManagedObjectContext is the handler we use to present model(NSMangedObject) to the out world, which includes data detail and relationship between data.
NSPersistentStoreCoordinator is like a traffic commander shows where the data could be CRUD for NSMangedObjectContext.
NSPersistentStore is the place knows how to store data, it will use SQLite and save the data on File System.
For most of the cases, single NSManagedObjectContext with single NSPersistentStore are widely used here.
So, what we actually use with View and Controller is NSManagedObjectContext. Let’s see how we create it.
1, Create NSManagedObjectContext.
self.managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
2, Add NSPersistentStoreCoordinator to NSManagedObjectContext.
self.managedObjectContext.persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[[NSManagedObjectModel alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"NestedTodoList" withExtension:@"momd"]]];
3, Add NSPersistentStore to NSPersistentStoreCoordinator.
NSError* error; [self.managedObjectContext.persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:[[[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:YES error:NULL] URLByAppendingPathComponent:@"db.sqlite"] options:nil error:&error]; if (error) { NSLog(@"error: %@", error); }
Then, your NSMangedObjectContext(self.managedObjectContext) is ready to use if no error ocurred.
0 notes
Text
How to compare objects of your custom NSObject subclass?
Comparison of any two NSObject objects or the objects of NSObject subclass could be very useful, when you are sorting, being unique in collection, or other cases. For example, you need to have your NSObject subclass objects added to or removed from a NSMutableSet, the Set needs to well identify which object is which, so there will be no duplicates. Then, the comparison of objects will be used to help.
How can we do it? Simple.
1st, Overwrite isEqual:(id)object function.
- (BOOL)isEqual:(id)object { if ([object isKindOfClass:[DeviceSensorStruct class]]) { DeviceSensorStruct *obj1 = (DeviceSensorStruct *)object; if (self.deviceID == obj1.deviceID && self.sensorID == obj1.sensorID) { return YES; } else { return NO; } } return NO; }
2nd, Give your object a meaning ful hash value.
- (NSUInteger)hash { return (int)(self.deviceID) * sizeof(unsigned char) + (int)(self.sensorID); }
0 notes
Text
How to Disable Default Popping Topmost UIViewController by Swipe from Left Edge
From iOS7, user could pop to parent UIViewController by swiping from screen’s left edge to some points in the middle. Also, UIScreenEdgePanGestureRecognizer is introduced since then, which could help develper add more ways to interact with the user.
Whlie, a question raised recently, how can I disable it?
The UIViewControllers are “Push” or “Pop” from the ViewController Stack, sometimes we call it UINavigationController. This is the entry where developer could use to access all the UIViewController in the Stack. Also, each UIViewController been pushed into the Stack will have an easy access to this UINavigationController.
Back to our question, how can we disable it?
After reading the iOS Developer Doc of UINavigationController, I found interactivePopGestureRecognizer Property, which is
The gesture recognizer responsible for popping the top view controller off the navigation stack. (read-only)
then, if we can disable this property, we could disable the user popping to parent UIViewController by swiping.
Here is the Code:
- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.delegate = self; } } - (void)viewWillDisappear:(BOOL)animated { if ([self.navigationController respondsToSelector:@selector(interactivePopGestureRecognizer)]) { self.navigationController.interactivePopGestureRecognizer.delegate = nil; } } - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer { return NO; }
Also, Add UIGestureRecognizerDelegate to the UIViewController.
0 notes
Text
WWDC2014 Video 221 Creating Custom iOS User Interface
In this video, four main topics are covered.
Sprint animations
Spring Animation is the base of almost every animation in the iOS8 system, which means almost all of the animations in iOS8 are using spring animation. It was introduced from iOS7 via one single function:
+ animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:
This function is very similar with ordinary animation function we used to using a lot. The only difference here is two additional parameters: Damping Ratio and Initial Spring Velocity. The damping ratio defines how much the oscillation oscillate at the end state of the animation, ranging from 0.0 to 1.0. 0.0 defines high frequency oscillation, while 1.0 defines no oscillation at all. This is place where can help us make a boucing effect. The initial spring velocity defines how fast the animation starts. The smaller the volecity is, the sooner the animation object will move to the end state, verse vice.
The following demo code imitate the Animation of Opening Folder on iOS Home Screen.
const static CGFloat BOXSIZE = 100.f; - (void)tapped:(UITapGestureRecognizer *)gesture { [self initBox]; [UIView animateWithDuration:1.f delay:0.f usingSpringWithDamping:.75f initialSpringVelocity:.5f options:0 animations:^{ [self endBox]; } completion:^(BOOL finished) { // }]; } - (void)initBox { self.movingBox.frame = CGRectMake(0.f, self.view.bounds.size.height - BOXSIZE, BOXSIZE, BOXSIZE); } - (void)endBox { self.movingBox.frame = CGRectMake(CGRectGetMidX(self.view.bounds) - BOXSIZE * 3.f / 2.f, CGRectGetMidY(self.view.bounds) - BOXSIZE * 3.f / 2.f, BOXSIZE * 3.f, BOXSIZE * 3.f); }
Vibrancy and blur
In iOS8, UIBlurEffect and UIVibrancyEffect are introduced for developers have Dynamic Blur Effect more easily. In the talk, Apple Engineer still recommends using static blur effect code if dynamic blur effect views are not actually what you need, since dynamic blur effect takes a lot of computer power.
The UIBlurEffect gives blur effect to an associated UIView, while UIVibrancyEffect gives the clear part which is not blurred on the blurred view. So, this is a three layer structure. UIView at the bottom, then comes the UIBlurEffect, at last the UIVibrancyEffect comes. The UIVibrancyEffect consumes the computing power most. The UIBlurEffect gives three styles for the developer to use, UIBlurEffectStyleExtraLight, UIBlurEffectStyleLight, UIBlurEffectStyleDark.
The example could be found at Siri User Interface, where user could clearly see the app icons on the Home Screen of the iPhone.
Shape layers
In this section, the engineer talks about the CAShapeLayer. Several things should be mentioned here:
How to use CAShapeLayer back up the UIView as the base layer. In UIView subclass,
+ (Class)layerClass { return [CAShapeLayer Class]; } - (void)awakeFromNib { CAShapeLayer *layer = (CAShapeLayer *)self.layer; // init layer properties here. // Also, everytime to update layer property, convert it to CAShaperLayer and use a local variable for it. }
How to draw part of the path for CAShapeLayer, by setting strokeStart and strokeEnd.
Dyanmic Core Animation behaviors
This is probably the most challenging part for me, so many sample code on CABasicAnimation. I think have a good use of CAAction delegate and CALayer Delegate method could greatly help your custom UIView subclass have great animation effect when UIView’s properties are changed. Also, developer could define customized property, which could be very powerful. By using this technique, developer could not only customize animation behavior, but also disable system’s default animation behaviors.
For more information, here is a link to the Apple Developer Official Page.
0 notes
Text
How to use NSShadow
As Apple iOS Documents mentions:
An NSShadow object may be used in one of two ways. First, it may be set, like a color or a font, in which case its attributes are applied to all content drawn thereafter—or at least until another shadow is applied or a previous graphics state is restored. Second, it may be used as the value for the NSShadowAttributeName text attribute, in which case it is applied to the glyphs corresponding to the characters bearing this attribute.
Thus, There TWO ways to implement NSShadow to your code.
1st, NSShadow could be set as attributes to all content drawn thereafter.
//// ShadowedRectangle.m// NSShadowDemo//// Created by Antonio081014 on 3/18/15.// Copyright (c) 2015 Antonio081014.com. All rights reserved. // #import "ShadowedRectangle.h" @implementation ShadowedRectangle - (instancetype)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.backgroundColor = [UIColor clearColor]; } return self; } - (void)drawRect:(CGRect)rect { UIFont *font = [UIFont boldSystemFontOfSize:30.f]; NSShadow *shadow = [[NSShadow alloc] init]; shadow.shadowColor = [UIColor redColor]; shadow.shadowBlurRadius = 0.0; shadow.shadowOffset = CGSizeMake(0.0, 2.0); NSDictionary *attributes = @{NSShadowAttributeName : shadow, NSForegroundColorAttributeName : [UIColor yellowColor], NSFontAttributeName : font, NSBackgroundColorAttributeName : [UIColor greenColor]}; NSAttributedString *attributedText = [[NSAttributedString alloc] initWithString:@"Text has shadows" attributes:attributes]; [attributedText drawInRect:rect]; } @end
2nd, NSShadow could be used as the value for the NSShadowAttributeName text attribute.
// Customize the UINavigationBar Title Font. NSShadow *shadow = [[NSShadow alloc] init]; shadow.shadowColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8]; shadow.shadowOffset = CGSizeMake(0, 1); [[UINavigationBar appearance] setTitleTextAttributes: [NSDictionary dictionaryWithObjectsAndKeys: [UIColor colorWithRed:245.0/255.0 green:245.0/255.0 blue:245.0/255.0 alpha:1.0], NSForegroundColorAttributeName, shadow, NSShadowAttributeName, [UIFont fontWithName:@"HelveticaNeue-CondensedBlack" size:21.0], NSFontAttributeName, nil]];
While, as seen on above examples, NSShadow could be easily applied to the Text as attributes, it could be also applied to images(pixels). Example could be found here.
If you want to read more, please check out http://www.antonio081014.com.
0 notes
Text
Customize UINavigationBar “Back Button”
Summary:
This article will try to dig a little bit about UINavigationController and UINavigationBar. The story starts with me trying customzie “Back Button” on UINavigationBar, which helps user to navigate back to precede ViewController.
Let’s start from scratch:
After creating a fresh new Xcode project with two ViewControllers(VC) on StoryBoard. User could easily navigate from one VC to another by clicking on the UIBarButtonItem on the UINavigationBar. The StoryBoard would look like the following:

When trying to run this simply application on iOS Simulator. User will realize the Title of Back Button on the second VC is not “First View Controller”, as it should be for most of the cases. Instead, it looks like:

“Back”, yes, the Title was changed by System automatically to “Back” because the Title of parent VC is too long.
If the Title of first VC is changed to “First”, then runnning application again, user would see:

So, when the Title of first VC is too long, the second VC will change the text of back button to “Back” automatically.
After a quick check with Reference of navigationItem of UIViewController. I could change the “back button” by using:
self.navigationItem.backBarButtonItem.title = @"Custom";
But doesn’t work at all. So another dig on this, found this:

So, basically it is saying the “Back Button” I wish to change is associated with Previous View Controller. Thus, the title of it should be changed in the “Parent View Controller”, not in Current View Controller. This blows my mind. Also, the reference of backBarButtonItem could be found by “Command + Clicking” on backBarButtonItem:

Then, the above code was moved to the “FirstVC.m” file.
But still nothing changed. Keep digging…
Based on several answers on StackOverflow.com, I realized the property navigationItem in UIViewController is readonly. So, I use this piece of code instead:
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Custom" style:UIBarButtonItemStylePlain target:nil action:nil];
This code totally rocks.
Conclusion:
Change backBarButtonItem in Parent ViewController. Not current ViewController.
Thanks for reading.
1 note
·
View note
Text
How to Calculate Weekday
There is an algorithm problem, asks which day is it? Ex. Monday, Tuesday, or Sunday.
There is one formula, which tells the answer very effieciently.
int week(int y, int m, int d){ if (m < 3) { m += 12; y--; } int w = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7; return w; }
The above is a C/C++ implementation code.
The following is a Swift implementation code.
func week(y:Int, m:Int, d:Int) ->Int { if (m < 3) { let m = 12 + m; let y = y - 1; } let w = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7; return w; }
0 notes
Text
How can we regain Focus
Choose a silence goal.
Find a quiet place.
Remove distractions.
Execute.
Repeat.
Ref: https://engineering.groupon.com/2015/misc/lightning-talk-silence-by-chris-powers/
0 notes
Text
Location Services Immigration from iOS7 to iOS8
With iOS7, I developed an app tracking all the location with other information like date, time, etc. Yes, right, it's like the other apps like "Life360", which could share the location with other family members. The app is backed with a local server developed with NodeJS and Database by MongoDB. All the techs are pretty freshly popular in current days. While, since iOS8 is pretty widely adapted by most of the users, I started to immigrate the app from iOS 7 to iOS 8. Here is what I did: 1st, I did nothing, simply run the source code on the iOS runned iPhone 5. The MapView shows exactly as before, which includes all the CLLocation fetched from the server. That means the history could be displayed fully on the Map. BUT, the current location annotation(That blue shining circle) doesn't show up. Also, my UIAlertView shows me the Location Service couldn't give me the location update even it tried to. 2nd, I read the Apple Reference, the most obviously differences I had found are the two newly coming functions which aim to request location service permission on the iDevice. I guess they must have the meaning to be here, I mean they are listed as the two functions in the first section on the page. So, I changed my code from - (void)startUpdatingLocation direct calling to having - (void)requestWhenInUseAuthorization first, then - (void)startUpdatingLocation in the delegate function - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status , when the status is kCLAuthorizationStatusAuthorized or kCLAuthorizationStatusAuthorizedWhenInUse, The result is the request function had been called but the status has been doomed to be kCLAuthorizationStatusNotDetermined . 3rd, After reading a post on StackOverflow, I found my answer. The reason I didn't have the NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key in Info.plist with a message to be displayed in the prompt. 4th, Everything is good, just like the old time. Summary: To Immigrate Location Service from iOS 7 to iOS 8, do these:
Call requestWhenInUseAuthorization or requestAlwaysAuthorization first.
Implement Delegate Function - (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
When status indicates the Location Service has been granted, Call startUpdatingLocation
Important: Add string message for NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription in your APPNAME-Info.plist under your support file folder.
Good Luck.
0 notes
Text
How to hide Hidden Files(Dot Files) on Mac
Open your Terminal.
defaults write com.apple.finder AppleShowAllFiles YES
Press alt, then right click on the "Finder", click "Relaunch".
0 notes
Text
HTTP Post with JSON on iOS
Ever since iOS5, the iOS supports the JSON parsing API. The NSJSONSerialization Class could convert JSON to Foundation objects, and convert Foundation objects to JSON. The Foundation objects supported in the API are NSDictionary, NSArray, NSString, NSNumber. (Checkout the Document for detail.)
So, making a HTTP Request on iOS, it requires a NSURLRequest(HTTP Request) configured appropriately, and the NSData to be sent to the server.
1st, Construct the NSData.
NSMutableDictionary *json = [[NSMutableDictionary alloc] init]; [json setValue:[NSString stringWithFormat:@"%d", 2] forKey:@"user_id"];
This piece of code would have a NSDictionary ready with Keys & Values.
NSError *e = nil; if (![NSJSONSerialization isValidJSONObject:json]) { NSLog(@"Invalid JSON format Data"); return nil; }
This piece checks if our constructed data is valid to be a JSON object to be converted.
NSData *data = [NSJSONSerialization dataWithJSONObject:json options:0 error:&e];
Then, this NSData object data is the data we will need to send to the server.
2nd, Configure the NSURLRequest
//1, Create NSURLSession. NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:nil delegateQueue:nil]; //2, Create NSURLRequest NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:4730/adddata"]]; // 3, Configure the Method of HTTP Request. [request setHTTPMethod:@"POST"]; // 3, Configure the Body(Data) of HTTP Request. [request setHTTPBody:[self postData]]; // 3, Configure the Header of HTTP Request. [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; // 4, Create DataTask with Callback function(Block) in it. The block will be fired once the server returns any data to the request. NSURLSessionDataTask *sessionDataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (error) { // Handle the error; NSLog(@"Error: %@", error.localizedDescription); } NSDictionary* json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error]; NSLog(@"Error: %@", error.localizedDescription); NSLog(@"Response POST: %@", json); dispatch_async(dispatch_get_main_queue(), ^{ self.display.text = [NSString stringWithFormat:@"%@\n%@", json, self.display.text]; }); }]; // 5, Fire the DataTask [sessionDataTask resume];
Here, the code
1st, Create a NSURLSession, which will generate a URLTask based on the URLRequest created later.
2nd, Create a NSURLRequest. Since we need to configure the request, then we make it mutable here. The exact URL is the string url, to which is the Restful API of the server.
3rd, Configure the Request with Method, Body(Data) and HTTPHeader.
4th, Create a DataTask which accomplishes the actual request operation. It has a Callback(Block) in it, which will be fired once the request accomplished, data will be received if the server returns any data, like confirmation data, etc.
5th, Fire the DataTask.
0 notes
Text
cURL HTTP GET & POST with a Node.js built Server
Recently, I have my server built with Node.js and MongoDB as the database.
Here comes the structure. The server is running in Node.js. MongoDB provides the database support. So the http requests will be accepted and handled by the node.js code. Based on the request, the server will insert, delete, query, or update the data in the database. People call this RESTFUL API. Even I don't know if there is another way to achieve this, it's just so native to me.
Once the basic server handling(API) code is done, it needs to be tested.
The most native way to test it is using a browser. Yes, that's what I use for testing if the server is running actively. I also use this to test my HTTP GET request.
Then, what should I do if I need to test with POST method?
Here comes cURL.
The format is like:
curl -X POST -H "Content-Type: application/json" -d '{"key":"val"}' URL
-d specify the actual Data of Posting Method.
-H specify the Content Type.
-X specify the Custom Request Method.
So, to send GET request, it would be like:
curl -X GET URL
BTW, using body-parser installed from npm, the parser could not parse the number with leading zeros. Also, every mongdb operation in nodejs must have a callback function.
0 notes
Text
How to Client IP Address in NodeJS
One single function could just solve your problem.
function getClientAddress(request) { with (request) return (headers['x-forwarded-for'] || '').split(',')[0] || connection.remoteAddress }
0 notes
Text
Custom Heart Shape CAShapeLayer to mask UIView
This is how it looks when the HeartShapeLayer applied to the UIView.
Check out the code on Github.
0 notes