Showing posts with label Apple. Show all posts
Showing posts with label Apple. Show all posts

Saturday, July 13, 2019

Swift - Notify ViewController from AppDelegate On FCM / APN

Hello,

Recently I tried  my hands on iOS app after long time as I had to convert one of our hybrid app to native app on urgent basis. There I had webview where I was loading my html app. On FCM message receieved we need to send URL received in FCM to webview and load the URL.

So here in this blog I will mention the procedure for it.

First of all in AppDelegate we have didReceiveRemoteNotification method. There we will create notification for it. Here is the code.


let url = dict
serverURL = url;
let notificationName = Notification.Name("updateWebView")
NotificationCenter.default.post(name: notificationName, object: nil)

Now in the ViewController where you want to make updates, subscribe to this notification in viewDidLoad function.

override func viewDidLoad() {
  let notificationName = Notification.Name("updateWebView")
  NotificationCenter.default.addObserver(self, selector:            #selector(ViewController.updateWebView), name: notificationName, object: nil)
}

And then add function in ViewController.

@objc func updateWebView() {
  let appDelegate = UIApplication.shared.delegate as! AppDelegate
  let serverURL = appDelegate.serverURL
        
  guard let url = URL(string: serverURL!) else {
     print("Invalid URL")
     return
  }
        
  let request = URLRequest(url: url)
  webView.load(request)
}

That's it and now you will have data passed from AppDelegate to ViewController. This method you can pass any kind of data from FCM to respective ViewController.

Hope this helps you.



Monday, May 29, 2017

Force Quit an App in Mac OSX from Terminal

Hello,

Recently I faced an issue with OpenOffice app on MAC. For some reason following open office window is displayed every time I open a document.


And then no matter what I do it does not go away. I tried force quit. Tried to close it from Activity monitor but it does not work. So then only option I had is to kill it with terminal. You can use this procedure to kill any unresponsive app in your OSX. 

First of all we have to find out process id of the unresponsive app. Since the app is unresponsive, it must be consuming lots of CPU resources. To find out this, open terminal and type following command.

top -o cpu

It will show following window. 


As you can see in first column we have PID and in second column we have app name. Find out PID from the name of unresponsive application and then type following command in terminal.

kill PID

 And it will kill unresponsive app. Hope this helps you.

Saturday, January 21, 2017

Xcode 8.2 Simulator Crash When Save Screen Shot - Alternate way to take Screenshot of iPhone simulator

I don't know what went wrong with my Xcode. Recently I was publishing an app in iTunes connect and for that I needed iPhone 7 screen shot. I opened simulator and run and app and tried to capture screenshot with Command + S and it crashed the simulator with following error and screen shot file was empty.



It shows some error related to some library of SwiftFoundation. I was not sure about this error. So first thing what I did is report it to apple and then tried few things like. Restarting simulator couple of times and restarting Xcode couple of times. But it didn't work. So may be it's related to SDK update. I updated the latest SDK but still it was not working. So at last I give it to Apple to solve the problem but I needed that screen shot. So here is alternate way to take Screenshot of iPhone simulator.

With simulator running. Select Go to Edit menu and Select Copy Screen.



This will copy current screen of simulator. Now open the preview and go to File and Select New From Clipboard.



And it will give you new image with copied screen of your simulator, now save it and use it with Preview. Hope this helps you.

Monday, January 9, 2017

10 Years of iPhone

Today is the one of the historical day for IT industry. Ten years ago today, on Jan. 9, 2007, Apple co-founder Steve Jobs, unveiled the product that would drive Apple to become the most valuable company in the world and cement Apple’s comeback as the greatest in business history. At the Macworld conference in San Francisco, he unveiled the iPhone.


Here is his Key note speech, in which he introduced iPhone.





Off course there was something crazy about iPhone. It changed mobile industry entirely and introduced Mobile Application economy with introduction of App Store, where developers can upload their apps and can make money. That created entire new opportunities for mobile application developers. Since it's introduction there are number of versions of iPhone are introduced with exciting features and cool UI display.

Being a mobile application developer I daily work with iOS devices and also other mobile devices here are some points which I feel are very spacial in iPhone.

Very Stable OS and Hardware support


Being a mobile application developer I work with both android and iOS devices but at one point every developer has to struggle with android while dealing with hardwares such as camera or SD card or any other native features. While in iPhone this is usually not the case because it has stable SDK and hardware which are manufactured by only Apple so we don't see much changes and customizations. While in case of android, since it's an open source operating system all the phone manufactures have changed it and customized it as per their platform. So face bit of problems while working with hardware. One app working without any issue in one phone may not work in other phone. While in case of iPhone, app will work all the devices and all the iOS versions.


Nice Development tools like Xcode IDE and Simulators


This is another advantage iOS development we have very stable Xcode IDE and iOS simulators using which we can develop applications very easily. In most of the cases you don't need real devices. Using simulators you can easily develop and test apps and launch in apple store. Xcode is not changed much since it's introduction and it's very easy to use, yes with the introduction of Swift, we have to learn new languages not but that's ok, that change is good.


It's not like iPhone is good in all the cases, there are some drawbacks.

Tooooo Expensive


This is first and foremost drawback for mobile application developer. Some features if you want to test like push notifications or cameras, that will work only in real devices and you have to buy it and it's too expensive for the developers. Developers can hardly afford one or two devices not more than that. Due to which sometime it gets hard to test some apps. As a mobile app developer I am still dreaming of having my own iPhone since years but I didn't manage to get it yet.

Bit Complex Testing Process and Publication Process


Compare to android, testing and publication process is bit complex in case of iOS. For Android you can share APK with any android devices and it can be installed and tested easily. While in case of iPhone, you need  apple developer account and create developer certificate and provisioning profile and register device Ids and upload app for testing and get it approved before you can send it to someone for testing using TestFight. Also to publish the app in market, you have to maintain some standards in case of UI and features, otherwise it's possible that your app may be rejected by app store and you have to redo again and make changes and republish app.


In short being a developer sometimes iPhone looks like blessing and sometime we feel that

Life Was Much Easier When Apple And Blackberry Were Just Fruits


Here is one funny video about it, Have fun and happy coding.


Saturday, January 2, 2016

Resolve App Transport Security Exceptions in iOS 9 and OSX 10.11

Hello,

Recently I was working on an old iOS application for my client. This app was developed on iOS 7 and we were adding few updates, I was using iOS 9 SDK on my Xcode. While development I found that none of the web services were working on app. In short app was not able to get data from remote URLs. I show the logs and there was App Transport Security Exception.

Let's first understand what is App Transport Security (ATS).

At WWDC 2015, Apple announced “App Transport Security” for iOS 9 and OSX 10.11 El Capitan. The “What’s New in iOS” guide for iOS 9 explains:

App Transport Security (ATS) lets an app add a declaration to its Info.plist file that specifies the domains with which it needs secure communication. ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt. You should adopt ATS as soon as possible, regardless of whether you’re creating a new app or updating an existing one.

If you’re developing a new app, you should use HTTPS exclusively. If you have an existing app, you should use HTTPS as much as you can right now, and create a plan for migrating the rest of your app as soon as possible.

In simple terms, this means that if your application attempts to connect to any HTTP server (in this example, yourserver.com) that doesn’t support the latest SSL technology (TLSv1.2), your connections will fail with an error like this:

CFNetwork SSLHandshake failed (-9801)
Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo=0x7fb080442170 {NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorCodeKey=-9802, NSUnderlyingError=0x7fb08055bc00 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1200.)", NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://yourserver.com, NSErrorFailingURLStringKey=https://yourserver.com, _kCFStreamErrorDomainKey=3}

In short app should have all the remote calls with Https protocol. How ever in my case it was not possible as my client refused to install SSL certificate. So I have to bypass App Transport Security.

So here how to do this. Open your project in Xcode and open info.plist file and add following key.

App Transport Security Settings



Now add one more key under that key which you added above. Following is the name of key.

Allow Arbitrary Loads and set it's value to YES. After adding both keys your info.plist should look as below.



That's it and now all your services should work with http protocols.



Send Apple Push Notifications (APN) from PHP Web Application

Hello,

In this blog I am going to explain how to configure your PHP server to send Apple Push Notifications (APN). Please note you will need a valid apple developer account for this.

First of all you will need a PEM file on your server. Following are the steps to create PEM file. Log into apple member center with your developer account credentials.

https://developer.apple.com/membercenter/index.action

Go to Certificates, Identifies & Profiles

Select iOS Apps - > Certificates

We will see how to create both development and production PEM file. Click on + sign on top right corner to add new certificate. It will show you list of certificate types.



Choose from development if you want development certificate or choose from production if you want production certificate. Click on Next and it will ask you to select your application in next step.



Select your desired application and click on next. Now you have to upload certificate signing request. Following are steps to generate certificate signing request


  • Open Keychain Access on your Mac (located in Applications/Utilities).
  • Open Preferences and click Certificates. Make sure both Online Certificate Status Protocol and Certificate Revocation List are set to Off.
  • Choose Keychain Access > Certificate Assistant > Request a Certificate From a Certificate Authority.
  • Note: If you have a private key selected when you do this, the CSR won’t be accepted. Make sure no private key is selected. Enter your user email address and common name. Use the same address and name as you used to register in the iOS Developer Program. No CA Email Address is required.
  • Select the options “Saved to disk” and “Let me specify key pair information” and click Continue.
  • Specify a filename and click Save.

Upload CSR in the following screen and click on continue.



In the next step click on generate and it will generate your certificate. Download certificate to your local machine and double click on it and it will be added to key chain access and it will open and should show you following screen.



As you can see above development certificates are added as Apple Development iOS Push Services and Production certificate are added as Apple Push Services. Now click on left arrow and expand it. You will see name of certificate signing authority there. Select both name and certificate and double tap on it it will show you following menu.



Click on export two items and save .p12 file.



Now we will convert .p12 file to .pem file using OpenSSL. Open your terminal and run following command.

openssl pkcs12 -in Certificates.p12 -out Certificates.pem -nodes -clcerts

That's it your pem file is ready. Upload it your server and add following functions to send APNs for production and development respectively in your PHP.

public function sendAPNProduction($deviceToken, $msg, $message){

        $payload['aps'] = array('alert' => $msg, 'badge' => 1, 'sound' => 'default');
        $payload['messages'] = $message;
        $payload = json_encode($payload);

        $apnsCert = 'Certicates.pem';

        $streamContext = stream_context_create();
        stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);

        $apns = stream_socket_client('ssl://gateway.push.apple.com:2195', $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);

        $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
        fwrite($apns, $apnsMessage);

        //socket_close($apns); seems to be wrong here ...
        fclose($apns);

}

public function sendAPNDevelopment($deviceToken, $msg, $message){

        $payload['aps'] = array('alert' => $msg, 'badge' => 1, 'sound' => 'default');
        $payload['messages'] = $message;
        $payload = json_encode($payload);

        $apnsCert = 'Certicates.pem';

        $streamContext = stream_context_create();
        stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);

        $apns = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);

        $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
        fwrite($apns, $apnsMessage);

        //socket_close($apns); seems to be wrong here ...
        fclose($apns);

}

That's it and now your PHP web app is ready to send Apple Push Notifications (APNs). I hope this helps you.








Sunday, May 3, 2015

Add iOS in App Purchase to Your Cordova Application

Hello,

Recently I was working on cordova application where we have to add in app purchase in iOS. In this blog I am going to explain how to add in app purchase to cordova based application.

First of all open your MainViewController.m file and un comment following function.


- (BOOL) webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType

As we are going to use above function to pass product id to native code from JavaScript with use of this function. Here is how to do this. From your JavaScript file add following code.

window.location.href = 'http://buyproduct.com?productId='+sku.toLowerCase();

This will invoke shouldStartLoadWithRequest delegate. Now in that delegate add following code.

NSURL *url = [request URL];
if([[url host]  isEqual: @"buyproduct.com"]){
        NSString *queryString = url.query;
        NSArray* queryStringValues = [queryString componentsSeparatedByString: @"&"];
        NSString* productId = [[[queryStringValues objectAtIndex:0] componentsSeparatedByString: @"="] objectAtIndex:1];
       return NO;
}

This way we get product id in native code and since we returned NO in that delegate, webview will not invoke this url.

Now let's add required library to support in App Purchase. First select project from project explorer and select build phases tab. At bottom where we have linked libraries click on + sign and search for storekit. It will show following framework. Add this to project.


Now open MainViewController.h file and add necessary import statements and delegates. Copy following code.

#import
#import
#import
#import

@interface MainViewController : CDVViewController <SKProductsRequestDelegate, UIAlertViewDelegate, SKPaymentTransactionObserver>
@property (retain, nonatomic) SKProduct* fetchedProduct;
@end
@interface MainCommandDelegate : CDVCommandDelegateImpl
@end

@interface MainCommandQueue : CDVCommandQueue
@end

Now open MainViewController.m file and add necessary callbacks.

#pragma mark -
#pragma mark SKProductsRequestDelegate methods

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    
}

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    SKPayment * payment = [SKPayment paymentWithProduct:fetchedProduct];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction * transaction in transactions) {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
            default:
                break;
        }
    };
}

- (void)completeTransaction:(SKPaymentTransaction *)transaction {
    
}

- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
    NSLog(@"restoreTransaction...");
    //call javascript function to consume product only
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

- (void)failedTransaction:(SKPaymentTransaction *)transaction {
    
    NSLog(@"failedTransaction...");
    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        NSLog(@"Transaction error: %@", transaction.error.localizedDescription);
    }
    
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

This are necessary functions to support transactions and product request. Now lets first request a product information. Go back to shouldStartLoadWithRequest and add following code at the end.

BOOL productPurchased = [[NSUserDefaults standardUserDefaults] boolForKey:productId];
        if (productPurchased) {
            //call javascript function to consume product
            [self.webView stringByEvaluatingJavaScriptFromString:@"consumePurchasedProduct();"];
        }else{
            SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
            productsRequest.delegate = self;
            [productsRequest start];
        }

Here we are checking if product already purchased. If already purchased simply call JavaScript function to consume it else start product request. After we get product information we have to show it to user.  Add following code to productRequest delegate.

NSArray *products = response.products;
    fetchedProduct = [products count] == 1 ? [products firstObject] : nil;
    if (fetchedProduct)
    {
        NSLog(@"Product title: %@" , fetchedProduct.localizedTitle);
        NSLog(@"Product description: %@" , fetchedProduct.localizedDescription);
        NSLog(@"Product price: %@" , fetchedProduct.price);
        NSLog(@"Product id: %@" , fetchedProduct.productIdentifier);
        
        NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
        [formatter setNumberStyle:NSNumberFormatterCurrencyStyle];
        [formatter setLocale:[NSLocale currentLocale]];
        NSString *localizedMoneyString = [formatter stringFromNumber:fetchedProduct.price];

        NSString *productPrice = @"Price : ";
        productPrice = [productPrice stringByAppendingString:localizedMoneyString];
        NSString* alertViewContent = fetchedProduct.localizedDescription;
        alertViewContent = [alertViewContent stringByAppendingString:@"\n \n"];
        alertViewContent = [alertViewContent stringByAppendingString:productPrice];
        UIAlertView * alert = [[UIAlertView alloc] initWithTitle:fetchedProduct.localizedTitle message:alertViewContent delegate:self cancelButtonTitle:@"Buy" otherButtonTitles:nil];
        [alert show];
    }

Above function will show alert like this with product information.


As you can see we have a buy button there. When user clicks on Buy it will call clickedButtonAtIndex function added in above code and it will start payment process. One payment is done it will call completeTransaction delegate. Add following code to it.

NSLog(@"completeTransaction...");
    [[NSUserDefaults standardUserDefaults] setBool:YES forKey:fetchedProduct.productIdentifier];
    //call javascript function to consume product
    [self.webView stringByEvaluatingJavaScriptFromString:@"consumePurchasedProduct();"];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

Here we are adding product to user defaults in case network got disconnected before user can consume product. In case of transaction failure other functions will be called.

Thursday, February 19, 2015

iOS Cordova Get Device Name

Hello,

Recently in one of my iOS app project, I had a requirement to get device name like "Hiren's iPhone". First I thought it's pretty simple as I checked device API documentation and saw that there is method device.name which should gave device name. I tried that and surprisingly it was returning undefined. I was not sure why it's not returning result. Then I saw source code and found out actually name property is not added in device API so I decided to add it. In this blog I am going to explain how to do this.

First open your CDVDevice.m file and find following function.


- (NSDictionary*)deviceProperties

In this function add following new line. 

[devProps setObject:[device name] forKey:@"name"];

That's it on objective C side. Now lets modify on JavaScript side. Open device.js file inside plugins/org.apache.cordova.device folder in your www folder. There is a constructor function 

function Device()

In this function first add name property. 

this.name = null;

And inside following function initialize this property.

channel.onCordovaReady.subscribe(function() {
        me.getInfo(function(info) {
        }
}

me.name = info.name;

That's it and now device.name should return your name of device set in settings.

Tuesday, February 17, 2015

iOS Today App Extension Widget Tap To Open Containing App

Hello,

Recently I added Today App Extension to one of my iOS app. In that we have a requirement to open containing app when user taps anywhere in app extension view. In this blog I am going to explain how to do this. First you have to add tap gesture recognizer to your main container view. In my case I had UIView as base container view. Inside this view I have added all other views.

So first create iboutlet property for that view. Now create Single Tap Gesture Recognizer.

UITapGestureRecognizer *singleFingerTap =
    [[UITapGestureRecognizer alloc] initWithTarget:self
                                            action:@selector(handleSingleTap:)];

[mainContainerView addGestureRecognizer:singleFingerTap];

As seen in above code, first we created singleFingerTap recognizer and added this as gesture recognizer to mainContainerView. Now add following function which we mentioned in selector.

- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
    NSURL *pjURL = [NSURL URLWithString:@"AppUrlType://home"];
    [self.extensionContext openURL:pjURL completionHandler:nil];
}

That's it. Simple.. isn't it? But wait, it won't work as we have to add URL type in our app. In iOS you can define custom URL schemes and URL types for your app. Using which you can open your app from browser or from some other app using openURL function as shown above in code. So let's add custom URL type for your app.

Open plist file of your main app and add new item with name URL types, expand item 0 of it and add new item with name URL Schemes. Expand item 0 of URL Schemes and add  "
AppUrlType" as a value. For your application, you can use any valid name. After adding this, you should have following structure in your plist file.


That's it. Now select your App Extension Target and run the widget. Tap anywhere in your widget and it will open your containing app. 

iOS App UI not updating in Main Thread

Hello,

Recently in one of my projects, I faced a very strange issue. I have an http service call in app which was in background which brings some data. I want to show those data in Textviews in UI. Now the issue was it was not updating UI properly. I had five textviews and five strings in five variables. Out of which it was updating only one Textviews. Rest of the views were not updated. I was not sure what was the issue here as I was updating UI on main thread but still it was not working. See the below code.


NSString *value1 = [jsonArray objectForKey:@"key1"];
NSString *value2 = [jsonArray objectForKey:@"key2"];
NSString *value3 = [jsonArray objectForKey:@"key3"];
NSString *value4 = [jsonArray objectForKey:@"key4"];
NSString *value5 = [jsonArray objectForKey:@"key5"];

As you see in above code I set five variables from my array which were created from JSON response of web service. Now I used dispatch_async to go on Main thread and set values to Text views.

dispatch_async(dispatch_get_main_queue(), ^{
       [txt1 setText:value1];
       [txt2 setText:value2];
       [txt3 setText:value3];
       [txt4 setText:value4];
       [txt5 setText:value5];
});

As I mentioned an issue above that, it was setting value of only first text views. Others were blank. So I was not sure what was the issue. Later I realized that it was nil problem. Since I used local variables to store data, by the time my code inside dispatch_async runs, the scope of those variables were destroyed and there was a nil value. So other text views were blank.

So the solution was to keep variable initialization inside  dispatch_async method. See the below code.

dispatch_async(dispatch_get_main_queue(), ^{
       NSString *value1 = [jsonArray objectForKey:@"key1"];
       NSString *value2 = [jsonArray objectForKey:@"key2"];
       NSString *value3 = [jsonArray objectForKey:@"key3"];
       NSString *value4 = [jsonArray objectForKey:@"key4"];
       NSString *value5 = [jsonArray objectForKey:@"key5"];

       [txt1 setText:value1];
       [txt2 setText:value2];
       [txt3 setText:value3];
       [txt4 setText:value4];
       [txt5 setText:value5];
});

That's it, it worked. After having initialization inside  dispatch_async method, all the text views values were displayed properly. Hope this will help you and save you time.

iOS Share Data Between iOS App and Today Widget (App Extension)

Hello,

Recently in one of my projects I implemented a Today Widget for the iOS application. While working on that I faced a situation where I have to get data stored in User Defaults of Main app to Today Widget. In this blog I am going to explain how you can sync data between app and widget.  In my case it was simple string data that was stored in user defaults.

For this, first you need to create an app group from Xcode. App group is group of apps which contains main app and an extension. When you create a group from Xcode, it will also create a group in developer portal. For that, first click on project in project explorer and select your main app target in Xcode and go to Capabilities - > App Groups. Initially app groups will be off, first you have to make it on and it will show a pop up window where you can create a new group. Group name always starts with group. prefix. See the image below.


Add your new group like this: group.companyname.groupname and click on Ok. It will sync with developer portal and create app group. Now select your app extension target and go to Capabilities - > App Groups. It will be off first. On it and it will sync with existing app groups which we created in first step. Add your app extension to this group. That's it. Now you can share data between app and app extensions. Now you have to add data by creating group defaults and saving data to groups. See the following code.  This code you can add to your main app.

NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:@"group.company.GroupDefaults"];
[shared setObject:[defaults objectForKey:@"key1"] forKey:@"value1"];
[shared setObject:[defaults objectForKey:@"key2"] forKey:@"value2"];
[shared synchronize];

As you can see in above code, we have created NSUserDefaults class instance with suite name or the group. Every time after adding objects to NSUserDefaults, you have to synchronize it. Else data will not be saved. Add following code to your app extension where you want to read data. 

NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:@"group.company.GroupDefaults"];
self.value1 = [shared objectForKey:@"key1"];
self.value2 = [shared objectForKey:@"key2"];

Also you can save other data in app extension and can read it in main app. 

[shared setObject:[defaults objectForKey:@"key3"] forKey:@"value3"];
[shared setObject:[defaults objectForKey:@"key4"] forKey:@"value4"];
[shared synchronize];

As I mentioned above, every time you have to sync after adding or modifying data in user defaults. Hope this will help you.



Tuesday, June 3, 2014

Introduction to Swift - the latest programming language from Apple

So Apple stunned all the developers around the globe by introducing new language instead of new iPhones, iPhones or iWatches. Let's see what exactly is the Swift.



Apple says the following about the release of Swift:

"Swift is a powerful new programming language for iOS and OS X® that makes it easier than ever for developers to create incredible apps. Designed for Cocoa® and Cocoa Touch®, Swift combines the performance and efficiency of compiled languages with the simplicity and interactivity of popular scripting languages. By design, Swift helps developers write safer and more reliable code by eliminating entire categories of common programming errors, and coexists with Objective-C® code, so developers can easily integrate Swift into their existing apps. Xcode® Playgrounds make writing Swift code incredibly interactive by instantly displaying the output of Swift code."

Swift code can live right besides C and Objective-C code in the same app. The syntax is quite similar to JavaScript. Here are some of the features of it.


  • Closures (similar to blocks in C and Objective-C) unified with function pointers
  • Tuples and multiple return values
  • Generics
  • Fast and concise iteration over a range or collection
  • Structs that support methods, extensions, protocols.
  • Functional programming patterns, e.g.: map and filter

Here is the first lesson of Swift. How to define a variable and a constant. Constants and variables must be defined before they are used. You can define constants with let keyword and variable with var keyword. For example

let maximumLoginAttemptsAllowed = 10
var currentLoginAttempt = 0

So here is a constant maximumLoginAttemptsAllowed which has a value 10 and a variable currentLoginAttempt which has value 0. 

Friday, October 12, 2012

How to add Tap Event to UIImageView in XCode?

Hello,

This blog post is about adding tap event to UIImageView dynamically.

Here we can use UITapGestureRecognizer class. Checkput the following code.


UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleImageTap:)];
        tap.cancelsTouchesInView = YES;
        tap.numberOfTapsRequired = 1;

Above code is to identify single tap on image. If you want to do it for double tap just increase the count by one in numberOfTapsRequired.

Now let's create our image view.

NSString *urlString = @"http://myurl.com/image.jpg";
NSURL *url = [NSURL URLWithString:urlString];
NSData *imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
UIView* mainServiceView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
UIImageView* imageView = [[UIImageView alloc] initWithImage:image];
imageView.userInteractionEnabled =TRUE;

Here note the last line imageView.userInteractionEnabled =TRUE; This is necessary else it will not respond to any gesture. Now add a gesture to image

[imagView addGestureRecognizer:tap];

Also add handleImageTap function to your view controller file.

- (void) handleImageTap:(UIGestureRecognizer *)gestureRecognizer {
    UIView* view = gestureRecognizer.view;
    //object of view which invoked this 
}



That's it now user can tap on your image.

Hope this helps you.





XCode- Send data and Close Popover from Master View Controller

Hello,

Recently I was working on the app, where there was a button in toolbar which opens the Pop over with a table view. After selecting table cell, we need to pass some information to master view controller and close the Popover.

First you need a reference in your master view controller. Add following to your View controller header file.


@property (nonatomic, strong) UIPopoverController *myPopOver;

Synthesize it in .m file.

@implementation masterViewController

@synthesize myPopOver; 
@end

Now add prepareForSegue method.

-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{ 
   
    if([segue.identifier isEqualToString:@"popOverSegue"]){
        UIStoryboardPopoverSegue *popoverSegue = (UIStoryboardPopoverSegue *)segue;
        self.myPopOver = popoverSegue.popoverController;
        [segue.destinationViewController setDelegate:self];
    }
    
}


Also add one call call back method in your master view controller, which will be invoked when user selects a cell in pop over table view.

-(void)myCallBack{
}

Now in pop over table view controller import your master view controller and set delegate as follow.

#import
#import "masterViewController.h"

@interface myPopOverController : UITableViewController 
@property (nonatomic, weak) masterViewController* delegate;
@end

Add following code to .m file

#import "myPopOverController.h"
#import "masterViewController.h"

@interface  myPopOverController ()<UITableViewDelegate>

@end

@implementation iPadCategoriesPopOver
@synthesize categoriesArray,categoriesTableView,delegate;

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    
        [[self delegate] myCallBack];
    
}


@end
Check above code carefully, here we have delegate of type mater view controller and using it to invoke our call back function, Above code is executed when some one selects a row from table view. Now add following code to myCallBack function to close the pop over.

[self. myPopOver dismissPopoverAnimated:YES];

Also note that you can pass any parameter in callback if you want.

Hope this helps you.











Parse JSON data in Objective C (iOS 5)

Hello,

Recently I was working on native iPAD app where we were having certain APIs which returns JSON data. This blog is about parsing JSON data in Objective C.

Following is the code to send request.


NSString *serviceURI = @"http://myapiturl.com";
    serviceURI = [serviceURI stringByAppendingString:sort];
    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
    [request setURL:[NSURL URLWithString:serviceURI]];
    [request setHTTPMethod:@"GET"];
    NSString *contentType = [NSString stringWithFormat:@"application/json"];
    [request addValue:contentType forHTTPHeaderField: @"Content-Type"];
    [request addValue:@"application/json" forHTTPHeaderField: @"Accept"];

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul);
    dispatch_async(queue, ^{
        NSURLResponse *response = nil;
        NSError *error = nil;
        
        NSData *receivedData = [NSURLConnection sendSynchronousRequest:request
                                                     returningResponse:&response
                                                                 error:&error];
        if(receivedData==nil){
            [SerenaNotifications showNetworkNotifcations];
        }else{
        }
});

Please note that here we are using GCD (grand central dispatch) I will explain this in other blog post. We will get our JSON data in receivedData variable. iOS 5 gives native classes for JSON serialization. Following code will go in else loop.

NSError *myError = nil;
            NSDictionary *res = [NSJSONSerialization JSONObjectWithData:receivedData options:NSJSONReadingMutableLeaves error:&myError];
            NSArray *resultArray = [res objectForKey:@"results"];

Normally in JSON request, results are added with results key. In your case if key is different, replace it in place of results.

This will give you all the results. If you have a single value in key you can access it as follow.

NSString* value = [object valueForKey:@"key"];

If you want to convert it to integer value. Use following code.

NSInteger intValue = [[object valueForKey:@"value"] intValue];



If you want to convert it to boolean value, use following code.

bool boolValue = [[object valueForKey:@"value"] boolValue];

Now you have all the results in resultArray. How to iterate through it and get a single object? Check the following code.

 NSEnumerator *e = [resultArray objectEnumerator];
            
            NSDictionary *object;
            while (object = [e nextObject]) {
             }

Object is the NSDictionary object having your single result object. Again you can use objectForKey and valueForKey methods of NSDictionary class in case you have nested JSON structure.

Hope this post helps you.