SimpList Privacy Policy

Privacy Policy of SimpList

Privacy Policy

Effective date: April 28, 2019

SimpList (“us”, “we”, or “our”) operates the SimpList mobile application (the “Service”).

This page informs you of our policies regarding the collection, use, and disclosure of personal data when you use our Service and the choices you have associated with that data. Our Privacy Policy for SimpList is created with the help of the Free Privacy Policy Generator.

We use your data to provide and improve the Service. By using the Service, you agree to the collection and use of information in accordance with this policy. Unless otherwise defined in this Privacy Policy, terms used in this Privacy Policy have the same meanings as in our Terms and Conditions.

Information Collection And Use

We collect several different types of information for various purposes to provide and improve our Service to you.

Types of Data Collected

Personal Data

While using our Service, we may ask you to provide us with certain personally identifiable information that can be used to contact or identify you (“Personal Data”). Personally identifiable information may include, but is not limited to:

  • Cookies and Usage Data

Usage Data

When you access the Service by or through a mobile device, we may collect certain information automatically, including, but not limited to, the type of mobile device you use, your mobile device unique ID, the IP address of your mobile device, your mobile operating system, the type of mobile Internet browser you use, unique device identifiers and other diagnostic data (“Usage Data”).

Tracking & Cookies Data

We use cookies and similar tracking technologies to track the activity on our Service and hold certain information.

Cookies are files with small amount of data which may include an anonymous unique identifier. Cookies are sent to your browser from a website and stored on your device. Tracking technologies also used are beacons, tags, and scripts to collect and track information and to improve and analyze our Service.

You can instruct your browser to refuse all cookies or to indicate when a cookie is being sent. However, if you do not accept cookies, you may not be able to use some portions of our Service.

Examples of Cookies we use:

  • Session Cookies. We use Session Cookies to operate our Service.
  • Preference Cookies. We use Preference Cookies to remember your preferences and various settings.
  • Security Cookies. We use Security Cookies for security purposes.

Use of Data

SimpList uses the collected data for various purposes:

  • To provide and maintain the Service
  • To notify you about changes to our Service
  • To allow you to participate in interactive features of our Service when you choose to do so
  • To provide customer care and support
  • To provide analysis or valuable information so that we can improve the Service
  • To monitor the usage of the Service
  • To detect, prevent and address technical issues

Transfer Of Data

Your information, including Personal Data, may be transferred to — and maintained on — computers located outside of your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from your jurisdiction.

If you are located outside United States and choose to provide information to us, please note that we transfer the data, including Personal Data, to United States and process it there.

Your consent to this Privacy Policy followed by your submission of such information represents your agreement to that transfer.

SimpList will take all steps reasonably necessary to ensure that your data is treated securely and in accordance with this Privacy Policy and no transfer of your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of your data and other personal information.

Disclosure Of Data

Legal Requirements

SimpList may disclose your Personal Data in the good faith belief that such action is necessary to:

  • To comply with a legal obligation
  • To protect and defend the rights or property of SimpList
  • To prevent or investigate possible wrongdoing in connection with the Service
  • To protect the personal safety of users of the Service or the public
  • To protect against legal liability

Security Of Data

The security of your data is important to us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While we strive to use commercially acceptable means to protect your Personal Data, we cannot guarantee its absolute security.

Service Providers

We may employ third party companies and individuals to facilitate our Service (“Service Providers”), to provide the Service on our behalf, to perform Service-related services or to assist us in analyzing how our Service is used.

These third parties have access to your Personal Data only to perform these tasks on our behalf and are obligated not to disclose or use it for any other purpose.

Links To Other Sites

Our Service may contain links to other sites that are not operated by us. If you click on a third party link, you will be directed to that third party’s site. We strongly advise you to review the Privacy Policy of every site you visit.

We have no control over and assume no responsibility for the content, privacy policies or practices of any third party sites or services.

Children’s Privacy

Our Service does not address anyone under the age of 18 (“Children”).

We do not knowingly collect personally identifiable information from anyone under the age of 18. If you are a parent or guardian and you are aware that your Children has provided us with Personal Data, please contact us. If we become aware that we have collected Personal Data from children without verification of parental consent, we take steps to remove that information from our servers.

Changes To This Privacy Policy

We may update our Privacy Policy from time to time. We will notify you of any changes by posting the new Privacy Policy on this page.

We will let you know via email and/or a prominent notice on our Service, prior to the change becoming effective and update the “effective date” at the top of this Privacy Policy.

You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted on this page.

Contact Us

If you have any questions about this Privacy Policy, please contact us:

Xcode 10 feature list

Performance

  • Editor loads large documents much faster(upto 2.5X faster)
  • Stability of in Source Kit and enhance the robustness of the language integration

Code completion and Navigation

  • Code completion now provides more targeted results and limits completion to high confidence matches
  • While navigating using Jump To Definition the destination list will now provide contextual details like file and line information

Source Control Change Bar

  • Change bar is on the left side of the editor and highlights the lines of code which has changed since your last checkout.
  • The style and color of the indicator revels the type of change, there are different color highlight color for Uncommitted, Upstream , Unpushed and Conflict changes.

Code Folding

  • Improved code folding, now you can code fold anything.
  • Code folding ribbon is back!

Multi cursor editing

  • Hold down Ctrl+Shift and click the places where you like to begin editing.
  • You can also do Column selection using holding down Option key.

More Source Control Integration

  • Support for Bitbucket and GitLab
  • Added support for Rebase during pull actions.

Energy Diagnostics Report

  • They are like Crash logs for energy usage of your application, it surface details for foreground and background energy usage of the app.

Testing

  • Test bundles can now be configured to execute their contents in a random order each time the tests are run. This can be enabled in the Test pane of the scheme editor as an option for each test bundle
  • Running tests in parallel. Test parallelization is supported for macOS unit tests, as well as unit and UI tests on iOS simulators

 

Apple Pay integration with Stripe tutorial

Why Apple Pay?

  • It’s an easy, secure and private way to pay within the app
  • One touch payment
  • No need to re enter payment or contact information
  • Private – cause credit card number are not exposed to the merchant, instead you are sent the device number and unique token that is only valid for that particular purchase.

Why use Apple Pay as developer?

  • You don’t need to handle credit card number
  • Higher conversion rate and faster checkout

Apple Pay  VS  In-App Purchase

  • Apple Pay is used for physical good’s & services where as In-App purchase is for in app content/functionality only
  • Developer is responsible of processing payment in Apple Pay where as Apple is responsible for processing payments in In-App purchase.

Prerequisites

iOS device (iPhone 6 or 6+, iPad Air 2, or iPad mini 3) running iOS 8.1 or later

Quick overview of how it works

  • You create a Merchant ID and matching certificate in Developer Portal
  • Your ID and certificate are used to encrypt the payment data
  • Display Payment sheet to user
  • User uses Touch ID to authorize transaction
  • Your app receives the payment token
  • This token is encrypted using your Merchant ID and certificate so only your application can decrypt it
  • Send token for processing using one of payment platforms like Stripe, Braintree, Shopify etc.

Create new Xcode Project

Screen Shot 2016-03-14 at 6.07.39 PM.png

Select “Single View Application” Template

Setup your app for ApplePay

Once project is created, login into your  http://developer.apple.com account. Go to Member Center and click on Certificates, Identifiers & Profiles\Identifiers\App IDs. Click on the + button to create a new App ID

Screen Shot 2016-03-14 at 6.13.23 PM

 

Screen Shot 2016-03-14 at 6.13.31 PM.png

Make sure that you select Explicit App ID is selected, as wildcard App IDs aren’t able to make payments with Apple Pay. Finally, check the Apple Pay checkbox under App Services, click Continue and then click Register to complete the creation of your new App ID.

Creating Merchant ID

Next click on Merchant ID under Identifiers pane. Then click on + or Continue to create new merchant ID for your app.

Screen Shot 2016-03-14 at 6.14.53 PM.png

Now that we have both Merchant ID and App ID we can head back to the Xcode Project

Under your project Capabilities turn on the Apple Pay option and add in your MerchantID

Screen Shot 2016-03-22 at 3.54.56 PM.png

The three items in the Steps section should all have checkmarks next to them to indicate that you’ve satisfied all of the requirements for using Apply Pay in your app.

In Main.Storyboard we are going to create textfield name, email and donation amount. We are also going to create a “Donate Again” button and Thank you message label, we are going to set there visibility hidden for now.

Screen Shot 2016-03-22 at 4.02.08 PM.pngScreen Shot 2016-03-22 at 4.02.30 PM.png

We are now going to create attached properties with these IBOutlets.We are also going to create UIButton property “payButton”which will be our ApplePay button later on. So our ViewController.h file now looks like this.

#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UITextField *userName;
@property (weak, nonatomic) IBOutlet UITextField *userEmail;
@property (weak, nonatomic) IBOutlet UITextField *donationAmount;
@property (weak, nonatomic) IBOutlet UILabel *thankYouMessage;
@property (weak, nonatomic) IBOutlet UIButton *donateAgainButton;
- (IBAction)donateAgainPressed:(id)sender;
@property (weak, nonatomic)  UIButton *payButton;
@end


The Apple Pay classes are part of PassKit, so you need that import to make things work.So lets add following right in our ViewController.h file.

@import PassKit;

Setting up Apple Pay button

Apple Pay is only available to a subset of iOS users. Before presenting the Apple Pay option to the current user, we are going to determine whether Apple Pay is available.

In ViewController.m file let put following

- (void)viewDidLoad {
 [super viewDidLoad];
 // Conditionally show Apple Pay button based on device availability
 if ([PKPaymentAuthorizationViewController canMakePaymentsUsingNetworks:@[PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkAmex]]) {
 _payButton = [self applePayButton];
 
 //Set location of Apple Pay button
 _payButton.frame = CGRectMake(_donationAmount.frame.origin.x, _donationAmount.frame.origin.y + _donationAmount.frame.size.height + 22.0, _payButton.frame.size.width, _payButton.frame.size.height);
 [self.view addSubview:_payButton];
 }else{
 //Create alternate payment flow
 }
}
- (UIButton *)applePayButton {
 UIButton *button;
 if ([PKPaymentButton class]) { // Available in iOS 8.3+
 button = [PKPaymentButton buttonWithType:PKPaymentButtonTypePlain style:PKPaymentButtonStyleBlack];
 } else {
 // Create and return your own apple pay button
 }
 [button addTarget:self action:@selector(tappedApplePay) forControlEvents:UIControlEventTouchUpInside];
 return button;
}

In this example we are not handling older versions of iOS, but if your app targets older iOS versions  you will need to create your own button using Apple’s Human Interface Guidelines and assets.

If we run our App now we will see the ApplePay button appear on our screen, but it doesn’t do anything yet.

Simulator Screen Shot Mar 22, 2016, 4.42.51 PM

Now let’s make the Apple Pay button work.For that we are going to implement PKPaymentAuthorizationViewControllerDelegate. We implement this protocol to respond to user interaction with the view controller.

@interface ViewController : UIViewController<PKPaymentAuthorizationViewControllerDelegate>

Implementing Delegates to Handle Payment Requests

We are going to implements the two required methods of the delegate in ViewController.m file:

- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didAuthorizePayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus))completion {
  //We are assuming right now that payment was successfull.
 completion(PKPaymentAuthorizationStatusSuccess);
}

- (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller {
 //we are going to make all fields blank after user is done paying or canceling payment
 _donationAmount.text = @"";
 _userEmail.text = @"";
 _userName.text = @"";
 
 [self dismissViewControllerAnimated:YES completion:nil];
}

Setting up PKPaymentRequest

PKPaymentRequest instance is responsible for displaying the Apple Pay payment sheet.We will fill in required PKPaymentRequest elements.

- (PKPaymentRequest *)paymentRequest:(NSString *)amount {
 PKPaymentRequest *paymentRequest = [[PKPaymentRequest alloc] init];
 paymentRequest.merchantIdentifier = @"merchant.com.xxxxxx";
 paymentRequest.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkVisa, PKPaymentNetworkMasterCard];
 paymentRequest.merchantCapabilities = PKMerchantCapability3DS;
 paymentRequest.countryCode = @"US";
 paymentRequest.currencyCode = @"USD";
 paymentRequest.paymentSummaryItems =
 @[
 [PKPaymentSummaryItem summaryItemWithLabel:@"Donation" amount:[NSDecimalNumber decimalNumberWithString:amount]],
 ];
 return paymentRequest;
}

Presenting Payment Sheet

When user taps on your Apple Pay button, we are going to present a PKPaymentAuthorizationViewController to initiate Apple Pay:

-(void)tappedApplePay{
 if ([self checkFormValid]){
 PKPaymentRequest *paymentRequest = [self paymentRequest:_donationAmount.text];
 PKPaymentAuthorizationViewController *vc = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest:paymentRequest];
 vc.delegate = self;
 [self presentViewController:vc animated:YES completion:nil];
 }else{
 //Showing Alert to user if all values are not filled
 UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"Please fill in all details" message:@"" preferredStyle:UIAlertControllerStyleAlert];
 
 UIAlertAction* ok = [UIAlertAction
 actionWithTitle:@"OK"
 style:UIAlertActionStyleDefault
 handler:^(UIAlertAction * action)
 {
 [alert dismissViewControllerAnimated:YES completion:nil];
 
 }];
 
 [alert addAction:ok];

 [self presentViewController:alert animated:YES completion:nil];
 }
}

-(BOOL)checkFormValid{
 BOOL valid = false;
 //We are doing some basic validation so we don't have amount blank while showing the payment sheet
 if ([_userName.text isEqualToString:@""] || [_userEmail.text isEqualToString:@""]|| [_donationAmount.text isEqualToString:@""]) {
 valid = false;
 }else{
 valid = true;
 }
 return valid;
}
Now lets run the app again and see the Apple Pay button in action. Once you fill in all the details and tap Apple Pay you should see the payment sheet with the option to pay with “Pay with Passcode”, if you are running this on iPhone you will see “Pay with TouchID” option.
Simulator Screen Shot Mar 28, 2016, 9.50.13 PM
Now only thing left to implement Stripe processing for Apple Pay.
Installing Stripe iOS SDK using CocoaPods
Let’s use CocoaPods to setup Stripe iOS library.  If you haven’t set up Cocoapods before, follow there installation instructions here. Then, add pod 'Stripe' to your Podfile, and run pod install. Close your project and use the .xcworkspace file to open your project in Xcode, instead of the .xcodeproj file, from here on out.
Screen Shot 2016-03-14 at 9.42.42 PM.png
Setting up Stripe for Apple Pay
Login/Register into your Stripe account and head to Apple Pay section of Account Setting.
Click on “Create New Certificate” and a .certSigningRequest file will automatically download.
Screen Shot 2016-03-14 at 10.27.01 PM.png
Now let’s head back to Apple Developer account. Click on Merchant ID under Identifiers pane and then click on Merchant ID we created for this app and hit edit.
Screen Shot 2016-03-14 at 10.29.23 PM.png
Upload the certificate downloaded from Stripe and hit continue.
Screen Shot 2016-03-14 at 10.29.45 PM.png
You’ll see a success page, with an option to download your certificate. Download it. Return to the Apple Pay section in Stripe dashboard and upload this .cer file to Stripe.
Screen Shot 2016-03-14 at 10.30.04 PM.png
Now our Stripe account is ready to work with Apple Pay.
Stripe API Keys
Get you test publishable API key from “API Keys” section of Account Setting. We will be setting it up in AppDelegate file, so it set for entire life cycle of the app.

Import Stripe in your AppDelegate.m file and setup publishable API key in method “didFinishLaunchingWithOptions”.

#import <Stripe/Stripe.h>
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
 [Stripe setDefaultPublishableKey:@"pk_test_key"];
 return YES;
}
Now lets add code to process the payment into Stripe Tokens. You can charge these tokens later in your server-side code.
In ViewController.m file lets import Stripe Libraries first.
#import <Stripe/Stripe.h>
Now in let change our PKPaymentAuthorizationViewControllerDelegate methods to handle stripe processing.
- (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller didAuthorizePayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus))completion {
 
 [self handlePaymentAuthorizationWithPayment:payment completion:completion];
 
}

- (void)handlePaymentAuthorizationWithPayment:(PKPayment *)payment completion:(void (^)(PKPaymentAuthorizationStatus))completion {
 [[STPAPIClient sharedClient] createTokenWithPayment:payment completion:^(STPToken *token, NSError *error) {
 if (error) {
 completion(PKPaymentAuthorizationStatusFailure);
 return;
 }
 [self createBackendChargeWithToken:token completion:completion];
 }];
}

- (void)createBackendChargeWithToken:(STPToken *)token completion:(void (^)(PKPaymentAuthorizationStatus))completion {
 //We are printing Stripe token here, you can charge the Credit Card using this token from your backend.
 NSLog(@"Stripe Token is %@",token);
 completion(PKPaymentAuthorizationStatusSuccess);
 //Displaying user Thank you message for payment.
 _thankYouMessage.hidden = false;
 _payButton.hidden = true;
 _donateAgainButton.hidden =false;
}
Last thing we are going to do is to implement “donateAgianPressed” method to allow user to pay again.
- (IBAction)donateAgainPressed:(id)sender {
 _payButton.hidden =false;
 _donateAgainButton.hidden= true;
 _thankYouMessage.hidden = true;
}
Lets run our app and see Apple pay in action
Simulator Screen Shot Mar 29, 2016, 3.29.50 PM
Simulator Screen Shot Mar 29, 2016, 3.29.51 PM
Simulator Screen Shot Mar 29, 2016, 3.29.55 PM
Here is the full source code for this tutorial.

Integrating Stripe in Swift with custom view

In this tutorial I am gonna integrate with Stripe without using STPView.

1) Start a new project

new-proj new-proj2

Make sure you select Swift as Language.

2) Add Stripe Framework to your Project

Follow the instructions provided by stripe to add framework to your project using Cocoapods.

If you decided not to use pods follow these instructions

Clone the iOS library repository directly:


git clone https://github.com/stripe/stripe-ios.git
  • In the menubar, click on ‘File’ then ‘Add files to “Project”…’.
  • Select the ‘Stripe’ directory in the downloaded repository.
  • Make sure ‘Copy items into destination group’s folder (if needed)’ is checked.
  • Click ‘Add’.
  • In your project settings, go to the “Build Phases” tab, and make sure Foundation.framework, Security.framework, and PassKit.framework are included in the “Link Binary With Libraries” section. If you’re targeting versions of iOS before iOS8, make sure PassKit.framework is listed as “Optional.”

copy-stripeadd-framework  setpasskit

 

Since Stripe framework is written in Objective-c we need to add Bridging-Header file to import files into project.

Create new file by selecting source as header file.header

 

Name the file YourProject-Bridging-Header, once file is created delete everything in that file and replace it with following code.


#import "Stripe.h"
@import Foundation;

 

After that switch to your project Build Settings and find Swift Compiler – Code Generation, and next to Objective-C Bridging Header add the path to your bridging header file, from the project’s root folder. So it will be YourProject/YourProject-Bridging-Header.h
brheader

 

3) Setup Stripe Account 

If you already don’t have a stripe account then create one at stripe.com, and get your publishable API key.

4) Create your credit card view

Build this using Interface builder.

creditcardview

 

Add following outlets in your ViewController file and hook it up with the view. Also hookup getStripeToken function with payButton.


    @IBOutlet var email: UITextField!
    @IBOutlet var cardNum: UITextField!
    @IBOutlet var exp: UITextField!
    @IBOutlet var cvc: UITextField!
    @IBOutlet var payButton: UIButton!
    
    @IBAction func getStripeToken(sender: AnyObject){

    }

Now let goto AppDelegate.swift file and add following lines and update application didFinishLaunchingWithOptions function



    
    let StripePublishableKey = "pk_test_your_key"


    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
            Stripe.setDefaultPublishableKey(StripePublishableKey)

        return true
    }

5) Get token from stripe

Lets update getStripeToken method to send data to stripe


@IBAction func getStripeToken(sender: AnyObject){
        let creditCard = STPCard() //creating a stripe card object
        creditCard.number = cardNum.text
        creditCard.cvc = cvc.text
        
        //extracting month and year values from expiry date 
        if (!exp.text.isEmpty){
            let expArr = exp.text.componentsSeparatedByString("/")
            if (expArr.count > 1)
            {
                var expMonth: NSNumber = expArr[0].toInt()!
                var expYear: NSNumber = expArr[1].toInt()!
                
                creditCard.expMonth = expMonth.unsignedLongValue 
                creditCard.expYear = expYear.unsignedLongValue
            }
        }
        
        var error: NSError?
        if (creditCard.validateCardReturningError(&error)){
            var stripeError: NSError!
            Stripe.createTokenWithCard(creditCard, completion: { (token, stripeError) -> Void in
                if (stripeError != nil){
                    println("there is error");
                }
                else{
                    self.cardNum.text = ""
                    self.exp.text = ""
                    self.cvc.text = ""
                    self.email.text = ""
                    
                     //shows your stripe token 
                    var alert = UIAlertController(title: "Your stripe token is: " + token.tokenId, message: "", preferredStyle: UIAlertControllerStyle.Alert)
                    var defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
                    alert.addAction(defaultAction)
                    self.presentViewController(alert, animated: true, completion: nil)
                }
            })
        }else{
           //shows alert if information is not correct
            var alert = UIAlertController(title: "Please enter valid credit card details", message: "", preferredStyle: UIAlertControllerStyle.Alert)
            var defaultAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
            alert.addAction(defaultAction)
            self.presentViewController(alert, animated: true, completion: nil)
            
        }

        
    }

iOS Simulator Screen Shot Jan 3, 2015, 11.19.26 PM

iOS Simulator Screen Shot Jan 3, 2015, 11.19.41 PM

So now you have your stripe token, you can send it some backend to process the payment.

You can download this project from github

Simple Parse Tutorial with Sprite Kit game

In this tutorial we are going to add scoring logic to Sprite Kit game we build in previous tutorial and save the score on Parse. Once the score is saved on Parse we are going to fetch the highest score for the user and display it.

Adding Scoring Logic to game

We are going to add a variable ‘player_score’ to keep track of user’s current score in MyScene.m


NSInteger player_score;

Our scoring logic is fairly simple, we give user a point on every missile appearing on the screen. You can pick any logic you like to calculate score for your game.


-(id)initWithSize:(CGSize)size {
    if (self = [super initWithSize:size]) {
        self.backgroundColor = [SKColor whiteColor];
        [self initalizingScrollingBackground];
        [self addShip];

        //Making self delegate of physics World
        self.physicsWorld.gravity = CGVectorMake(0,0);
        self.physicsWorld.contactDelegate = self;
        player_score = 0; //initializing score as zero
    }

    return self;
}

-(void)addMissile
{
    //initalizing spaceship node
    SKSpriteNode *missile;
    missile = [SKSpriteNode spriteNodeWithImageNamed:@"red-missile.png"];
    [missile setScale:0.15];

    //Adding SpriteKit physicsBody for collision detection
    missile.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:missile.size];
    missile.physicsBody.categoryBitMask = obstacleCategory;
    missile.physicsBody.dynamic = YES;
    missile.physicsBody.contactTestBitMask = shipCategory;
    missile.physicsBody.collisionBitMask = 0;
    missile.physicsBody.usesPreciseCollisionDetection = YES;
    missile.name = @"missile";

    //selecting random y position for missile
    int r = arc4random() % 300;
    missile.position = CGPointMake(self.frame.size.width + 20,r);

    player_score = player_score + 1; //adding to score when ever new missile is created
    [self addChild:missile];

}

We have to update our initWithSize and addMissile methods to incorporate scoring logic.

Now we want to display score at the end of game screen. To do that we going to modify our GameOverScene.m initWithSize method and add declaration in GameOverScene.h

GameOverScene.h


#import <SpriteKit/SpriteKit.h>

@interface GameOverScene : SKScene

-(id)initWithSize:(CGSize)size score: (NSInteger)player_score;

@end

GameOverScene.m



#import "GameOverScene.h"
#import "MyScene.h"
#import <Parse/Parse.h>

@implementation GameOverScene
-(id)initWithSize:(CGSize)size score: (NSInteger)player_score{ //updated the existing method
    if (self = [super initWithSize:size]) {

        // 1
        self.backgroundColor = [SKColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];

        // 2
        NSString * message;
        message = @"Game Over";
        // 3
        SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        label.text = message;
        label.fontSize = 40;
        label.fontColor = [SKColor blackColor];
        label.position = CGPointMake(self.size.width/2, self.size.height/2);
        [self addChild:label];

        NSString * retrymessage;
        retrymessage = @"Replay Game";
        SKLabelNode *retryButton = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        retryButton.text = retrymessage;
        retryButton.fontColor = [SKColor blackColor];
        retryButton.position = CGPointMake(self.size.width/2, 50);
        retryButton.name = @"retry";
        [retryButton setScale:.5];

        [self addChild:retryButton];

        NSString * playerscoremsg = [NSString stringWithFormat:@"Player Score: %ld",(long)player_score];

        SKLabelNode *playerscore = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        playerscore.text = playerscoremsg;
        playerscore.fontColor = [SKColor blackColor];
        playerscore.position = CGPointMake(self.size.width/2, 250);
        playerscore.name = @"Player Score";
        [playerscore setScale:.5];

        [self addChild:playerscore];        
    }
    return self;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch *touch = [touches anyObject];
    CGPoint location = [touch locationInNode:self];
    SKNode *node = [self nodeAtPoint:location];

    if ([node.name isEqualToString:@"retry"]) {
        SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];

        MyScene * scene = [MyScene sceneWithSize:self.view.bounds.size];
        scene.scaleMode = SKSceneScaleModeAspectFill;
        [self.view presentScene:scene transition: reveal];

    }

}
@end

In GameOverScene.m we have added another label which is displaying players score. Before we try out our scoring logic we need to make one more change in MyScene.m


- (void)didBeginContact:(SKPhysicsContact *)contact
{
    SKPhysicsBody *firstBody, *secondBody;
    if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask)
    {
        firstBody = contact.bodyA;
        secondBody = contact.bodyB;
    }
    else
    {
        firstBody = contact.bodyB;
        secondBody = contact.bodyA;
    }

    if ((firstBody.categoryBitMask & shipCategory) != 0 &&
        (secondBody.categoryBitMask & obstacleCategory) != 0)
    {
        [ship removeFromParent];
        SKTransition *reveal = [SKTransition flipHorizontalWithDuration:0.5];
        SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size score:player_score]; //updated this method so we can send players score to game over scene.
        [self.view presentScene:gameOverScene transition: reveal];

    }
}

Now we are ready to run our app and test out scoring logic.

iOS Simulator Screen shot Jan 13, 2014 11.39.01 PM

Saving Score on Parse

Download Parse SDK and follow the steps given in this guide to add Parse Framework to your app.

Once you have added Parse framework to your app, create a account on Parse.

Login to you account to get started.

create_new_app

Once you have created a new app, navigate to setting tab and copy Application ID and ClientKey.app-keys-big

Once you have the key copied Navigate to Data Browser to start creating your database.

create-new-table

After adding the class we going to add columns to PlayerScore class.

create-custom

We are going to add first column user_id which takes string value. Add another column ‘score’ which take number value.

new-table

Your class should look like this at the end.

Alright now are ready to add Parse related code in our app.

Step 1) Adding Parse Keys to app.

In AppDelegate.m update method didFinishLaunchingWithOptions to following


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [Parse setApplicationId:@"Application Key" //replace these values with keys you got from Parse account
                  clientKey:@"Client Key"];
    
    return YES;
}

Step 2) Push user score to Parse at end of the game.

Before we push user score to Parse we need a way to identify individual user, which we are going to save in “user_id” column in our Parse Class. We are going to use users “identifierForVendor” as unique identifier for now.

identifierForVendor:  The value of this property is the same for apps that come from the same vendor running on the same device. A different value is returned for apps on the same device that come from different vendors, and for apps on different devices regardless of vendor. You can read more about it here.

Note:  Every time you delete the app from your simulator and install it again you are going to get a different ID. So you will be considered as different user every time you delete the app and install it again.

We are going to update GameOverScene.m initialization method with the following code.



-(id)initWithSize:(CGSize)size score: (NSInteger)player_score{
    if (self = [super initWithSize:size]) {

        self.backgroundColor = [SKColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];

        NSString * message;
        message = @"Game Over";

        SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        label.text = message;
        label.fontSize = 40;
        label.fontColor = [SKColor blackColor];
        label.position = CGPointMake(self.size.width/2, self.size.height/2);
        [self addChild:label];

        NSString * retrymessage;
        retrymessage = @"Replay Game";
        SKLabelNode *retryButton = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        retryButton.text = retrymessage;
        retryButton.fontColor = [SKColor blackColor];
        retryButton.position = CGPointMake(self.size.width/2, 50);
        retryButton.name = @"retry";
        [retryButton setScale:.5];

        [self addChild:retryButton];

        NSString * playerscoremsg = [NSString stringWithFormat:@"Player Score: %ld",(long)player_score];

        SKLabelNode *playerscore = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        playerscore.text = playerscoremsg;
        playerscore.fontColor = [SKColor blackColor];
        playerscore.position = CGPointMake(self.size.width/2, 250);
        playerscore.name = @"Player Score";
        [playerscore setScale:.5];

        [self addChild:playerscore];

        UIDevice * currentDevice = [UIDevice currentDevice];
        NSString *deviceIDString = [currentDevice.identifierForVendor UUIDString]; //getting unique id for the user

        NSNumber *playerScoreNum = [NSNumber numberWithInt:player_score]; //converting score into NSNumber format in which Parse expect the score

       PFObject *scoreObject = [PFObject objectWithClassName:@"PlayerScore"];
        [scoreObject setObject:deviceIDString forKey:@"user_id"]; //user's unique id

        [scoreObject setObject:playerScoreNum forKey:@"score"]; //user's score 

        [scoreObject saveInBackground]; //saving in background, so our application is not halted while saving the score.

    }
    return self;
}

If you run the code now, you will at the end of the game your score is getting pushed to Parse.

Data Browser   Parse

Step 3)  Fetch score from Parse and display the highest score so far

We are going to fetch all previous scores of current user and sort them descending order to get the highest score on top. We are going to add the following lines to GameOverScene.m initialization method.


-(id)initWithSize:(CGSize)size score: (NSInteger)player_score{
    if (self = [super initWithSize:size]) {

        self.backgroundColor = [SKColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];

        NSString * message;
        message = @"Game Over";

        SKLabelNode *label = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        label.text = message;
        label.fontSize = 40;
        label.fontColor = [SKColor blackColor];
        label.position = CGPointMake(self.size.width/2, self.size.height/2);
        [self addChild:label];

        NSString * retrymessage;
        retrymessage = @"Replay Game";
        SKLabelNode *retryButton = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        retryButton.text = retrymessage;
        retryButton.fontColor = [SKColor blackColor];
        retryButton.position = CGPointMake(self.size.width/2, 50);
        retryButton.name = @"retry";
        [retryButton setScale:.5];

        [self addChild:retryButton];

        NSString * playerscoremsg = [NSString stringWithFormat:@"Player Score: %ld",(long)player_score];

        SKLabelNode *playerscore = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"];
        playerscore.text = playerscoremsg;
        playerscore.fontColor = [SKColor blackColor];
        playerscore.position = CGPointMake(self.size.width/2, 250);
        playerscore.name = @"Player Score";
        [playerscore setScale:.5];

        [self addChild:playerscore];

        UIDevice * currentDevice = [UIDevice currentDevice];
        NSString *deviceIDString = [currentDevice.identifierForVendor UUIDString]; 

        NSNumber *playerScoreNum = [NSNumber numberWithInt:player_score]; 

        PFQuery *query = [PFQuery queryWithClassName:@"PlayerScore"]; //creating query for Parse
        [query whereKey:@"user_id" equalTo:deviceIDString];
        [query orderByDescending:@"score"]; //Sorting the score so we have highest score on the top

        [query findObjectsInBackgroundWithBlock:^(NSArray *scoreArray, NSError *error) {

            NSNumber* hightestScore = [scoreArray.firstObject objectForKey:@"score"]; //highest score is first object
            NSLog(@"highest score %@ devise %@",hightestScore, deviceIDString);

            if (hightestScore < playerScoreNum){
                hightestScore = playerScoreNum; //if highest score so far is smaller than current score, display current score
            }
            NSString * highscoremsg = [NSString stringWithFormat:@"Highest Score: %@",hightestScore]; 

            SKLabelNode *highscore = [SKLabelNode labelNodeWithFontNamed:@"Chalkduster"]; //Displaying highest score label
            highscore.text = highscoremsg;
            highscore.fontColor = [SKColor greenColor];
            highscore.position = CGPointMake(self.size.width/2, 200);
            [highscore setScale:.5];
            [self addChild:highscore];

        }];

       PFObject *scoreObject = [PFObject objectWithClassName:@"PlayerScore"];
        [scoreObject setObject:deviceIDString forKey:@"user_id"];

        [scoreObject setObject:playerScoreNum forKey:@"score"];

        [scoreObject saveInBackground];

    }
    return self;
}

We are querying for the highest score in the background so that it does not halt the flow of the app, and user is displayed other information without a delay. We only create the label for highest score once the data is fetched from Parse.

Now run the app and see your highest score.

iOS Simulator Screen shot Jan 20, 2014 1.55.36 PM

 

I hope this was helpful.  You can download the code for this tutorial here.

Getting gravatar images with Ruby on Rails

What Is Gravatar?

An “avatar” is an image that represents you online—a little picture that appears next to your name when you interact with websites.A Gravatar is a Globally Recognized Avatar. You upload it and create your profile just once, and then when you participate in any Gravatar-enabled site, your Gravatar image will automatically follow you there.

Understanding how to get images from Gravatar

When you sign up in gravatar, you need to register an unique e-mail. Gravatar uses that email address to generate an unique MD5.hexdigest key, and then, it links that key to your image file.

Let’s take a look at my gravatar  image url:

http://gravatar.com/avatar/1c7b91342323ab699f6668f3317ed1bb

Parameter after the avatar is the MD5.hexdigest key generated with your email, let’s try generate that in our application and check if it gives the same result:


require "digest/md5"
Digest::MD5.hexdigest('meghagulati30@gmail.com').to_s

Result is “1c7b91342323ab699f6668f3317ed1bb”

So now you can write your own tool to get the gravatar user image: just use the email to generate the key and append it to the url.

If you are looking for more options while fetching the image you can use gems like gravtastic which lets you get images of different sizes, avatar rating and different filetype.