It was the very first civic hackathon at Pasadena, and they wanted to innovate means to utilize technology in society. The city has a profound and fantastic API anyone can readily use to make some awesome apps (http://data.cityofpasadena.net/home/).
So for the event, I entered with the goal to utilize and practice APNS, since I had not previously. I'm not going to lie: APNS is like faith, and you don't know what's going on. Unlike faith, there are some more down to earth metrics that make APNS concrete, although, it may not seem that way from the beginning. At the heart of APNS is SSL, and at the heart of SSL are certificates.
The trick is this, now listen carefully, the settings on the provisioning profile must match the application exactly, and they are both critical to setting up the environment for APNS.
I utilized a nice piece of code written for Node.js (http://orderoo.wordpress.com/2012/03/01/apple-push-notifications-on-heroku-using-node-js-8/), and refactored it a bit.
The product was successful, and at the end, #hackforpasadena was a great event. If ever there's a trivia question "who was the second human in the history of Pasadena civic hackathons to present a project?" the answer is me 8]
Wikipedia
Search results
16 March 2014
04 March 2014
OAuth primer for iOS
So tonight I had a nice discussion with a colleague about OAuth. We had a nice review on OAuth.. and the take home point (please correct below!) is that OAuth is a user authentication protocol. there is v1 and v2.. v2 differs in that you can make requests to the app with a token.
Nevertheless, you pass over the user authentication process over to the OAuth protocol, and leverage that the user can utilize their other account(s) at popular and common services.
So we proceeded to create a makeshift OAuth controller.
We will be accessing the user login with UIWebView, the endpoint for OAuth services generates HTML that allows the user to log in to the host's Users database. So let's declare our variables:
On loadView (yes, no storyboard or xib), let's go ahead and make everything, the page is a webView that loads the authorization endpoint of Meetup, and a token and key are required for this to work. Therefore, I previously created my account, and generated an application utilizing their console.
(void) goMeetup is a delegate method I call in my other view controller:
I'm utilizing a helper method to parse the response. I want the userId, and to make a request of that user with that value. Therefore, if the value exists, then I will request the details of that user:
Each service has a unique API and enpoints. There will be variations in the flow, and in the case of Social Framework and others there are abstracted convenience methods to reach the same goal. You can see, such as with the Google + API that utilizes OAuth2, that the process looks quite different from the previously demonstrated example. These abstractions that are available in the Frameworks will handle the presentation of the user login dialog, and the ability to make changes to the user's entry in the host User database:
Nevertheless, you pass over the user authentication process over to the OAuth protocol, and leverage that the user can utilize their other account(s) at popular and common services.
So we proceeded to create a makeshift OAuth controller.
We will be accessing the user login with UIWebView, the endpoint for OAuth services generates HTML that allows the user to log in to the host's Users database. So let's declare our variables:
@interface LoginViewController ()@property (strong, nonatomic) UIWebView* webView; @property (strong, nonatomic) NSNumber* userId; @end
On loadView (yes, no storyboard or xib), let's go ahead and make everything, the page is a webView that loads the authorization endpoint of Meetup, and a token and key are required for this to work. Therefore, I previously created my account, and generated an application utilizing their console.
- (void)loadView
{
[super loadView];
UIButton* exit = [UIButton buttonWithType:UIButtonTypeRoundedRect];
exit.backgroundColor = [UIColor clearColor];
[exit setTitle:@"X" forState:UIControlStateNormal];
[exit addTarget:self action:@selector(exit) forControlEvents:UIControlEventTouchUpInside];
exit.frame = CGRectMake(20, 20, 44, 44);
[self.view addSubview:exit];
_webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, self.view.bounds.size.height, self.view.bounds.size.width, self.view.bounds.size.height)];
_webView.delegate = self;
[self.view addSubview:_webView];
}
(void) goMeetup is a delegate method I call in my other view controller:
- (void)goMeetup
{
NSString* scope = [NSString stringWithFormat:@"https://secure.meetup.com/oauth2/authorize?client_id=%@&response_type=code&redirect_uri=%@", MEETUP_CLIENTID, @"http://www.filmproj.com"];
CGRect newRect = self.view.bounds;
[_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:scope]]];
[UIView animateWithDuration:0.3f animations:^{
_webView.frame = newRect;
}];
}
I'm utilizing a helper method to parse the response. I want the userId, and to make a request of that user with that value. Therefore, if the value exists, then I will request the details of that user:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSLog(@"request url lastpathComponent = %@", request.URL.lastPathComponent);
NSString *html = [webView stringByEvaluatingJavaScriptFromString:
@"document.body.innerHTML"];
NSString* part = [self scanString:html startTag:@"MM.Member={" endTag:@"\
"];
NSString* anId = [self scanString:part startTag:@"id:" endTag:@","];
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
self.userId = [f numberFromString:anId];
if (self.userId) {
[self userApi];
} else {
[self alertError];
}
return YES;
}
- (NSString *)scanString:(NSString *)string startTag:(NSString *)startTag endTag:(NSString *)endTag
{
NSString* scanString = @"";
if (string.length > 0) {
NSScanner* scanner = [[NSScanner alloc] initWithString:string];
[scanner scanUpToString:startTag intoString:nil];
scanner.scanLocation += [startTag length];
[scanner scanUpToString:endTag intoString:&scanString];
}
return scanString;
}
- (void)userApi
{
NSString* urlString = [NSString stringWithFormat:@"https://api.meetup.com/members?member_id=%@&key=%@", self.userId, MEETUP_KEY];
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlString]] queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
if (data) {
NSDictionary* dictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
//NSLog(@"dictionary = %@", dictionary);
if (dictionary) {
NSDictionary* userResponse = [dictionary valueForKey:@"results"][0];
//NSLog(@"userResponse = %@", userResponse);
if (userResponse) {
NSString* city = [userResponse valueForKey:@"city"];
NSString* country = [userResponse valueForKey:@"country"];
NSString* name = [userResponse valueForKey:@"name"];
NSString* state = [userResponse valueForKey:@"state"];
NSString* avatarUrl = [userResponse valueForKey:@"photo_url"];
NSArray* topicsArray = [userResponse valueForKey:@"topics"];
NSMutableArray* topicsArrayHolder = [NSMutableArray array];
for (NSDictionary* json in topicsArray) {
NSLog(@"topicsArray = %@", topicsArray);
NSNumber* jsonId = [json valueForKey:@"id"];
NSString* jsonName = [json valueForKey:@"name"];
NSString* jsonUrlKey = [json valueForKey:@"urlKey"];
MeetupTopic* topic = [[MeetupTopic alloc] initWithTopicId:jsonId name:jsonName urlKey:jsonUrlKey];
[topicsArrayHolder addObject:topic];
}
[[UserAuthenticated sharedInstance] makeUserWithId:self.userId username:name city:city state:state country:country imageUrl:avatarUrl andTopics:topicsArrayHolder];
[topicsArrayHolder removeAllObjects];
// tests for user authenticated object
NSNumber* user0 = [[UserAuthenticated sharedInstance] userId];
NSString* user1 = [[UserAuthenticated sharedInstance] userName];
NSString* user2 = [[UserAuthenticated sharedInstance] city];
NSString* user3 = [[UserAuthenticated sharedInstance] state];
NSString* user4 = [[UserAuthenticated sharedInstance] country];
NSArray* user5 = [[UserAuthenticated sharedInstance] topicsArray];
UIImage* user6 = [[UserAuthenticated sharedInstance] avatar];
NSLog(@"%@\n%@\n%@\n%@\n%@\n%@\n%@", user0, user1, user2, user3, user4, user5, user6);
// dismiss controller
// update ui on other pages, and enable features
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[self alertError];
});
}
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[self alertError];
});
}
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[self alertError];
});
}
}];
}
- (void)alertError
{
[[[UIAlertView alloc] initWithTitle:nil message:@"err, if it's not you it's me" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show];
}
@end
Each service has a unique API and enpoints. There will be variations in the flow, and in the case of Social Framework and others there are abstracted convenience methods to reach the same goal. You can see, such as with the Google + API that utilizes OAuth2, that the process looks quite different from the previously demonstrated example. These abstractions that are available in the Frameworks will handle the presentation of the user login dialog, and the ability to make changes to the user's entry in the host User database:
- (void)goGoogle
{
GPPSignIn *signIn = [GPPSignIn sharedInstance];
signIn.delegate = self;
signIn.shouldFetchGoogleUserEmail = YES;
signIn.clientID = GOOGLE_CLIENTID;
signIn.scopes = [NSArray arrayWithObjects:kGTLAuthScopePlusLogin,nil];
signIn.actions = [NSArray arrayWithObjects:@"http://schemas.google.com/ListenActivity",nil];
[signIn authenticate];
}
- (void)finishedWithAuth: (GTMOAuth2Authentication *)auth
error: (NSError *) error
{
NSLog(@"Received error %@ and auth object %@",error, auth);
NSString *urlStr = @"https://www.googleapis.com/oauth2/v1/userinfo?alt=json";
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[auth authorizeRequest:request
completionHandler:^(NSError *error) {
NSString *output = nil;
if (error) {
output = [error description];
} else {
// Synchronous fetches like this are a really bad idea in Cocoa applications
//
// For a very easy async alternative, we could use GTMHTTPFetcher
NSURLResponse *response = nil;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (data) {
// API fetch succeeded
output = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
}
NSLog(@"output:%@",output);
}
}];
}
26 February 2014
Outline of Efficient Market View and Behavioral Finance View
Efficient Market View
- financial markets are efficiently taking account of all information, market prices reflect data
- "security prices reflect the true underlying value of assets"
- little room to capitolize on markets
Technical Analysis
- looking at charts to identify patterns in movements in markets
- Head and shoulder pattern, indicates great potential future loss (1% of cases)
- stock prices have to do a random walk through time (99% of cases)
- random walk:
x(t) = x(t-1) - E
E = random number
random walk negates trends
random walk states there is no regressing mean
- AR1 (first order autoregressive)
x(t) = 100 + p(x(t-1) - 100) + E
if (p = 1) AR1 = random walk
the larger the value of p (as p approached 1), the more random it is
** strategy
if below trend line => buy
if above trend line => sell
** prices will revert back to trend
Behavioral Finance/Economics
Adam Smith (1759) Theory of Moral Sentiments
(1776) Wealth of Nations
"praise is a fundamental human desire"
"humans make a transition from a desire for praise to a desire for praise worthiness"
Prospect Theory (Kahneman & Tversky)
value function = how people value items
reference point is subject to manipulation
wealth
framing (verbal manipulation/spin)
weighting function = how people deal with probabilities
probability
value between 1 and 100
others:
regret
overconfidence
cognitive dissonance
ego holding to false beliefs
assembling evidence that supports false theory
social contagion
herd behavior
collective consciousness (Emile Durkheim)
zeitgeist = collective set of facts/collective memory
Investments
1) Investment Allocations
- architectural makeup of investments
2) Market Timing Portfolios
- decisions over time
3) Security Selection
- risks vs reward
- financial markets are efficiently taking account of all information, market prices reflect data
- "security prices reflect the true underlying value of assets"
- little room to capitolize on markets
Technical Analysis
- looking at charts to identify patterns in movements in markets
- Head and shoulder pattern, indicates great potential future loss (1% of cases)
- stock prices have to do a random walk through time (99% of cases)
- random walk:
x(t) = x(t-1) - E
E = random number
random walk negates trends
random walk states there is no regressing mean
- AR1 (first order autoregressive)
x(t) = 100 + p(x(t-1) - 100) + E
if (p = 1) AR1 = random walk
the larger the value of p (as p approached 1), the more random it is
** strategy
if below trend line => buy
if above trend line => sell
** prices will revert back to trend
Behavioral Finance/Economics
Adam Smith (1759) Theory of Moral Sentiments
(1776) Wealth of Nations
"praise is a fundamental human desire"
"humans make a transition from a desire for praise to a desire for praise worthiness"
Prospect Theory (Kahneman & Tversky)
value function = how people value items
reference point is subject to manipulation
wealth
framing (verbal manipulation/spin)
weighting function = how people deal with probabilities
probability
value between 1 and 100
others:
regret
overconfidence
cognitive dissonance
ego holding to false beliefs
assembling evidence that supports false theory
social contagion
herd behavior
collective consciousness (Emile Durkheim)
zeitgeist = collective set of facts/collective memory
Investments
1) Investment Allocations
- architectural makeup of investments
2) Market Timing Portfolios
- decisions over time
3) Security Selection
- risks vs reward
20 November 2013
Update UICollectionView as a batch
1) get all the data you need
2) create array of index paths
3) update your view
sample code:
2) create array of index paths
3) update your view
sample code:
NSArray* dataArray = // however you get the data
if (dataArray.count == 0) {
moreTaps = NO;
return;
}
NSMutableArray* indexArray = @[].mutableCopy;
NSInteger dataSourceCount = arrayDisplay.count;
for (int i = 0; i < dataArray.count; i++) {
if ([indexHolderArray containsObject:[[dataArray objectAtIndex:i] anId]]) {
continue;
}
[arrayDisplay addObject:[dataArray objectAtIndex:i]];
NSInteger indexPathItem = i + dataSourceCount;
[indexArray addObject:[NSIndexPath indexPathForRow:indexPathItem inSection:0]];
}
dispatch_sync(dispatch_get_main_queue(), ^{
[_collectionView insertItemsAtIndexPaths:indexArray];
});
27 September 2013
Writing Pascal Triangle in Scala
The Pascal Triangle has some basic ground rules, all based on it's final/original structure:
1 The first column/row is 1
11 Where column = row is 1
121 The inside variables are a sum of the above row (row - 1), and neighbor to it's left (row - 1, column - 1)
1331
14641
Granted we are dealing with integers, we can formulate the above logic with a little Scala as:
def pascalLogic(r:Int, c:Int) =
// if first column/row or column = row
if (c == 0 || r == c) 1
// else sum of values
else pascalLogic(r-1, c) + pascalLogic(r-1, c+1)
To print out the pretty Pascal Triangle sans spaces, print the integer result for each message, and create line breaks at all instances where (r == c):
for (r <- 0 to c by 1) {
for (c <- 0 to r by 1)
print(pascalLogic(r, c) + " ")
println()
}
Combining the pieces :
def drawPascalTriangle(c:Int) { // curly brace creates closure/block/scope
for (r <- 0 to c by 1) {
for (c <- 0 to r by 1)
print(pascalLogic(r, c) + " ")
println()
def pascalLogic(r:Int, c:Int):Int =
if (c == 0 || r == c) 1
else pascalLogic(r-1, c) + pascalLogic(r-1, c-1)
}
}
drawPascalTriangle(12) COMMON RECURSIVE PATTERNS
- Linear (eg factorial)- Tree (eg Fibonacci, counting change)
- Primes and GCD
// factorial
def fac(x:Int, acc:Int):Int =
if (x == 0) 1
else if (x == 1) acc
else fac(x-1, acc * x)
// fibonacci
def fibo(n:Int):Int =
if (n==0) 0
else if (n==1) 1
else fibo(n-1) + fibo(n-2)
// counting change
def countChange(money:Int, coins:List[Int]):Int =
if (money == 0) 1 else if (money < 0 || coins.isEmpty) 0 else {
countChange(money - coins.head, coins) + countChange(money, coins.tail)
}
23 August 2013
Sails Tutorial for iOS
Sails Tutorial for iOS
How to get started developing full stack applications with Sails
We are going to make an application for the iPhone in XCode v4.6 that displays messages from the Sails server to the iPhone. To get started, install Sails:
Now that you have Sails installed, let's create a sails project. The first thing we will do is create the Xcode project. In Xcode, create a Single View application, and give it the name SampleAppSails.
Open Terminal, and go to your Xcode project's folder. Mine was on the desktop, and my path was '/User/aug2uag/desktop/SampleAppSails'. Once you are in your Xcode project directory, create the Sails application. Note, that we could have initially created the Sails application, and included the Xcode project in that directory. Since the Sails directory includes multiple other directories, I opted to organize it as mentioned above.
To create your new Sails project, in terminal type:
sails new sailsXcodeProject
You will notice Sails installs with many features right away. Among these are automagically generated RESTful API requests that we will be using for our application. Let's open our Sails project files, and inspect these elements.
In /config you will find the filename controllers.js that includes instructions for a blueprint. The blueprint is a prototype for the actual Sails application. Here, the blueprint for the app is specified to include:
// Automatic REST blueprints enabled?
// e.g.
// 'get /:controller/:id?'
// 'post /:controller'
// 'put /:controller/:id'
// 'delete /:controller/:id'
rest: true,
Here, the Sails application has by default set to yes for including methods in the controllers you will create. If you like to disable the default methods, and write your own custom methods, then you can set the parameter to false.
For the purposes of the application we are developing, the default controller methods will be selected to perform our actions. Specifically, we will want to:
-
POST a message to the server, that includes our text and userId
GET the messages from the server, and display them as a list on the iPhone
sails g Messages
This has created the Messages model, and controller. Let's open the model from the /api directory, and add the following attributes:
module.exports = {
attributes: {
text: 'string'
}
};
This says that we will be storing Messages objects on the server, and that the messages object will consist of text. Note that a timestamp will be generated automatically each time a new object is produced. We will incorporate the timestamp to our view output later. For now, let's move on, and take a look at the MessagesController.js file found in the /api directory.module.exports = {
sayHello: function (req, res) {
res.send('hello world!');
}
};
There is a simple Hello World function to demonstrate the functional style language used in Sails that is common to Node. You can call this function via a GET request to the route with the corresponding name of the function you want to call. Each function operates in a block, and that makes it possible for the program to continue without the need for the result of the function to return. We will be sticking with the default controller methods, and those are abstracted away from us, unless we had decided to write our own custom methods.Let's link up a Mongo database to hold our information. I already have my Mongo shell running on port 27017, please fire up your mongod, and in the /config/session.js file add the following:
module.exports.session = {
secret: '7309c3e86f54d10dbcdf2b4e113ab393', //automatically generated by Sails for each application
adapter: 'mongo',
host: 'localhost',
port: 27017,
db: 'sails',
collection: 'sessions'
};
We are telling Sails that for our project (secret: value is automatically generated for each application), we are going to be using (adapter: mongo), in path (host & port: local/27017), a database named 'sails' that stores collections.
Save everything, and run your Sails application, and you should see your sails application operating on localhost:1337. You can also verify your app is running by opening a new shell, and running:
curl http://localhost:1337Let's move on, and create the iPhone client.
Your SampleApplicationSails.xcodeproj should be open on XCode. Go to your storyboard or xib file, and add:
-
tableView
textField
button
@interface ViewController ()
{
SocketIO* socketIO;
__weak IBOutlet UITextField *oTextField;
__weak IBOutlet UITableView *oTableView;
NSArray* sailsArray;
}
- (IBAction)submitText:(id)sender;
@end
Create your tableViewDataSource methods, with logic to handle the empty array (i.e. since it may be initially empty):
#pragma mark-table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if (sailsArray.count == 0) {
return 1;
}
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
oLabel.hidden = YES;
});
return sailsArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"id"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"id"];
}
if (sailsArray.count == 0) {
cell.textLabel.text = @"array does not exist (yet)";
return cell;
}
//declare string, assign to value at indexPath from array
//array may be made from [dictionary allKeys];
NSString* string = [[sailsArray objectAtIndex:indexPath.row] valueForKey:@"text"];
//set string to textLabel of cell
[cell.textLabel setText:string];
[cell.detailTextLabel setText:subString];
return cell;
}
To connect to our server (that should be running in the background), we need to create a socket to communicate to the server, and establish connection to the server's controller methods. Since Sails ships with Socket.io, we will establish the socket with Socket.io for Objective-C. Add the Socket.io files from Socket.IO / Objective C Library on Github.
To your ViewController.h @interface, add
#import "SocketIO.h"
Make ViewController conform to the SocketIO delegate methods by adding SocketIODelegate next to your ViewController.
In your ViewController.m file, create a SocketIO instance variable name socketIO. In the ViewController.m @implementation viewDidLoad, add the following:
socketIO = [[SocketIO alloc] initWithDelegate:self];
[socketIO connectToHost:@"localhost" onPort:1337];
Run your Xcode project, and let's see what happens. Take a look at your shell running your Sails application, and you will notice that we received an error that no handshake occured. To address this, we will make a call to the Sails application prior to establishing the socket. In your ViewController.m, add the following before your code that instantiates your SocketIO object:
//handshake
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://localhost:1337/"]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:10];
[request setHTTPMethod: @"GET"];
NSError *requestError;
NSURLResponse *urlResponse = nil;
NSData *response1 = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&requestError];
Also add the following to view the results of the GET request:
//converts response to string (index.html)
NSString* stringFromData = [[NSString alloc] initWithData:response1 encoding:NSUTF8StringEncoding];
NSLog(@"data converted to string ==> string = %@", stringFromData);
Run your Xcode project again, and you should see a log that displays the contents of your /views/home/index.ejs file in your Sails directory.We will send a POST request to the server for the message we will type in our TextField. We will limit the size of our input by using the UITextField delegate method
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
In your viewDidLoad set the oTextField.delegate to self, and in the ViewController.m file, add the following:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSUInteger newLength = [textField.text length] + [string length] - range.length;
if (newLength>30) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Your Text" message:@"is too lengthy" delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
return NO;
}
return YES;
}
We are limiting the textField to 30 characters, and sending an alert if the count is higher than our limit. So once we have that in place, we can create our submit POST action. To your button action method, add the following:
- (IBAction)submitText:(id)sender
{
NSMutableURLRequest *request = [NSMutableURLRequest
requestWithURL:[NSURL URLWithString:@"http://localhost:1337/messages"]];
NSString* inputString = oTextField.text;
NSString *params = [[NSString alloc] initWithFormat:@"text=%@&createdAt=%@", inputString, createdAt];
oTextField.text = nil;
[request setHTTPMethod:@"POST"];
[request setHTTPBody:[params dataUsingEncoding:NSUTF8StringEncoding]];
[[NSURLConnection alloc] initWithRequest:request delegate:self];
}
We will evaluate the response by logging it to our console via the NSURLConnection delegate. Declare a NSMutableData variable to your ViewController.m @interface. Add the following to implement your NSURLConnection delegate:
#pragma mark - NSURLConnectionDelegate
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
mutableData = [NSMutableData data];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[mutableData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"response => %@",[[NSString alloc] initWithData:mutableData encoding:NSUTF8StringEncoding]);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"Error");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:error.localizedDescription delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
}
Run your Xcode project again, and you should see the status of your POST request to the server.
Now that we can access when the POST request did finish, we will call the server to recieve a list of the messages on the server to display on the tableView. To do this, we will send a GET request to the Messages controller of our Sails application, and assign the result to our NSArray variable we defined a while back. When we refresh our tableView, the results are now displayed.
In Summary
Sails is an amazingly efficient, and user-friendly technology to turn your iOS applications in to something so much more. The automagic REST integration allows for simple CRUD operations out of the box. For more references, please browse the online documentation. Cheers!11 August 2013
NSURLConnectionDelegate snippet
#pragma mark - NSURLConnectionDelegate
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
mutableData = [NSMutableData data];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[mutableData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSLog(@"mutableArray in finishedLoading => %@", [[NSString alloc] initWithData:mutableData encoding:NSUTF8StringEncoding]);
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
NSLog(@"Error");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:error.localizedDescription delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil];
[alert show];
}
Subscribe to:
Posts (Atom)