Showing posts with label iOS Tips & Tutorials. Show all posts
Showing posts with label iOS Tips & Tutorials. Show all posts

Thursday, January 7, 2016

Xcode Tip- Show Blame for line

If you are working on the project with multiple developer and found some bug in a line then you can check who was responsible for committing it using the Xcode feature.

You just need to right click on the line and tap “Show blame for line”, it will show the popup with the Developer name who committed the line along with Commit message.



Wednesday, November 25, 2015

How to check API availability in Swift?

If you are working with Swift then you need to be very careful to use the iOS specific API. As before Swift 2.0, there were no standard way to check the availability of any API or method.

Swift 2.0 introduced the “#available“ to check the API availability or run version specific code in blocks . If you are developing the application with deployment target 8.0 with base sdk 9.0. You need to use the API which is available in iOS 9 only then you could do this by checking the API availability. 

If you will not check the API availability then it will give you a compiler error. To prevent this error, you need to check the API availability.

if #available(iOS 9, *) {
            let stackView = UIStackView()
            // do iOS 9 stuff
        }

Using the availability syntax we will check whether we are running iOS 9 or later and if so will execute the code.

You can also add the availability check for the instance method and classes by inserting the given line above the method definition or at the top of the class.

@available(iOS 8.0, *)
    func iOS8Method() {
        // do stuff
        
    }

You can’t use this method without availability check if your deployment target is below 8.0. This method will run above iOS8.0 target. 

The * at the end is used to refer all the Future platforms that Apple introduces, and it's required.



Tuesday, March 10, 2015

How to create custom operators in Swift?

In Swift, you can create your own custom operators in additions to the Swift operators. 

Swift has Unary, Binary and Ternary Operators. You can create the custom operators for Unary and Binary operators. For Unary operators, you can use Prefix and Postfix modifier and for Binary Operator, you can use Infix modifier.

Currently, we cannot write the Custom Ternary operators. Swift has only one Ternary Operator that is Condition operator.
eg- a ? b: c

Following are the modifier which you can use to create the custom operators. 

Prefix- A Unary Operator that is placed before the operand.
eg- b = ++a (++ is operator and a is operand)

Postfix- A Unary Operator that is placed after the operand.
eg- b = a++

Infix- A Binary operator that is placed in between the two operands.
eg- c = a + b

You can create the custom operators that starts with one of the ASCII characters /, =, -, +, !, *, %, <, >, &, |, , or ~, or any of the Unicode characters in the "Math Symbols" character set.

Note-  As mentioned in the Apple documentation, there are some operators which can’t be overloaded nor can be used as Custom Operators. 
The tokens =, ->, //, /*, */, ., the prefix operators <, &, and ?, the infix operator ?, and the postfix operators >, !, and ? are reserved. These tokens can’t be overloaded, nor can they be used as custom operators.

Implementing a Prefix and postfix operator-

As you know that Unary operator operates on single operand. It can be Prefix (++a) if they precede the operand or Postfix (a++) if they follows the operand.

You can implement your own custom unary operators by preceding the operators function with the prefix and postfix modifier.

Let’s declare the +++  prefix operator which can doubles the operand’s value.

prefix operator +++ {}

Now, define the operator functions.

prefix func +++ (number: Double) -> Double {
    return (number + number)
}

let value = +++10 // 20

In the same way, you can create the unary operator with  the postfix modifier.




Implementing an Infix Operator- 

Infix operator is operates on two operators and placed in between the two operands. When you declare the custom Infix operators you can specify the Associativity and Precedence. 

If there are two or more infix operators in the expressions then on the basis of Associativity and Precedence, it can be define which infix operator executes first.

Here, we have define the new custom infix operator +- with left associativity and 140 precedence.

Associativity value can be left, Right and None. By default it is None and the precedence value is 100 if it is not specified. 

infix operator +- { associativity left precedence 140 }

Now, implements the +- operator which returns the tuple value of sum and difference of two operands.

func +- (left: Double, right: Double) -> (Double, Double) {
    return (left + right, left - right)
}

let value = 3 +- 2 // (5, 1)






Thursday, January 29, 2015

How to open Share and Action Extension from your application?


With the introduction of Extension in iOS 8, many applications is available with Share and Action Extension and if we want to share content and perform some action from our application to those app then we can open the extensions of those application using UIActivityViewController.

UIActivityViewController is a standard view controller which can offers System specific services such as copying items to the pasteboard, posting content to social media sites, sending items via email or SMS from your application.

Below is the code to initiate UIActivityViewController.

let text = "Text to share"
        let url : AnyObject! = NSURL(string: "https://www.google.co.in")
        let image : AnyObject = UIImage(named:"download.jpeg")!
        let activityItems : [AnyObject] = [text, url, image]
        
        let activityViewController : UIActivityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
        self.presentViewController(activityViewController, animated: true, completion: nil)


Here, we have created array of AcitivityItems(image, text, url) and passed it to the UIActivityViewController Constructor.

This will show all the Share and Action Extension supported by the system or application which are installed in your devices.




Note- User can manually enable and disable the application by tapping the More shown in the Share and Action Activity section. User can also reorder this activities.



     
There are 2 types of activities- Share and Action. Following are the activities for which system has built in supports-

 UIActivityTypePostToFacebook;
 UIActivityTypePostToTwitter;
 UIActivityTypePostToWeibo;
 UIActivityTypeMessage;
 UIActivityTypeMail;
 UIActivityTypePrint;
 UIActivityTypeCopyToPasteboard;
 UIActivityTypeAssignToContact;
 UIActivityTypeSaveToCameraRoll;
 UIActivityTypeAddToReadingList;
 UIActivityTypePostToFlickr;
 UIActivityTypePostToVimeo;
 UIActivityTypePostToTencentWeibo;
 UIActivityTypeAirDrop;

By Default, UIActivityViewController will show all the available activities. If you want to exclude any of the activity from your application then you can do this by passing the array of activities which you want to exclude to excludedActivityTypes property of UIActivityViewController.

        activityViewController.excludedActivityTypes = [UIActivityTypeAirDrop];

Here, we have excluded AirDrop to be shown in our application.




You can also check when the activity has been completed by calling completionWithItemsHandler.

 activityViewController.completionWithItemsHandler = {
            (activity, success, items, error) in
            println("Activity: \(activity) Success: \(success) Items: \(items) Error: \(error)")
        }

This is the complete method which you can use in your application and connect the action with the Button.
  
    @IBAction func shareAction(sender: AnyObject) {
        
        let text = "Text to share"
        let url : AnyObject! = NSURL(string: "https://www.google.co.in")
        let image : AnyObject = UIImage(named:"download.jpeg")!
        let activityItems : [AnyObject] = [text, url, image]
        
        let activityViewController : UIActivityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil)
        activityViewController.excludedActivityTypes = [UIActivityTypeAirDrop];
        self.presentViewController(activityViewController, animated: true, completion: nil)
        
        activityViewController.completionWithItemsHandler = {
            (activity, success, items, error) in
            println("Activity: \(activity) Success: \(success) Items: \(items) Error: \(error)")
        }
        
    }


Download the complete Project from here.

Monday, January 19, 2015

How to use both Objective C and Swift in same Project


With the introduction of new language Swift, developers can use this language to develop the iOS project. But most of the APIs are available in Objective C. So if any developer is developing the project in Swift language and they wants to use these Objective C API in there project then they can do it.

Even Developers can create the project with mix and match of both languages Objective C and Swift.

This post will tell you how you can use both language in the application.


Use Objective C in Your Swift project-

If you want to use Swift file in your Objective C project, just create a Objective C file and Xcode will prompt you asking “Would you like to create Objective C Bridging Header?”





When you tap on Yes it will create a Bridging Header file with name "ProductName-Bridging-Header.h"

You can import your Objective C code to Swift by importing your header file in this Bridging header file.





Use Swift in Your Objective-C project-


In order to use Swift file in your Objective C project, just create a Swift file by selecting File> New > Swift.



Now Xcode will prompt you asking “Would you like to create Objective C Bridging Header?”
 You can import your Swift code to any Objective C file by using this syntax-

#import “ProjectName-Swift.h”



You can download the sample app from Github.



Monday, October 13, 2014

How to add overlay to Video?



Sometimes you want to add overlay to the captured video for adding copyright label & watermark image.

You can use AVFoundation framework which provides the ability to edit the captured video. Using this framework, we can edit & add the watermark image & text over the captured video. 

You can use this method by passing the image & video url. You should pass the image which you want to add as a overlay  to the captured video. This method will export the new video with watermark image over the video.


- (void) createWatermark:(UIImage*)image video:(NSURL*)videoURL
{
if (videoURL == nil)
return;
AVURLAsset* videoAsset = [[AVURLAsset alloc]initWithURL:videoURL options:nil];
AVMutableComposition* mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack* compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo  preferredTrackID:kCMPersistentTrackID_Invalid];
AVAssetTrack* clipVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
  ofTrack:clipVideoTrack
atTime:kCMTimeZero error:nil];
[compositionVideoTrack setPreferredTransform:[[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] preferredTransform]];
//  create the layer with the watermark image
CALayer* aLayer = [CALayer layer];
aLayer.contents = (id)image.CGImage;
aLayer.frame = CGRectMake(50, 100, image.size.width, image.size.height);
aLayer.opacity = 0.9;
//sorts the layer in proper order
AVAssetTrack* videoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
CGSize videoSize = [videoTrack naturalSize];
CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
[parentLayer addSublayer:videoLayer];
[parentLayer addSublayer:aLayer];
// create text Layer
CATextLayer* titleLayer = [CATextLayer layer];
titleLayer.backgroundColor = [UIColor clearColor].CGColor;
titleLayer.string = @"Dummy text";
titleLayer.font = CFBridgingRetain(@"Helvetica");
titleLayer.fontSize = 28;
titleLayer.shadowOpacity = 0.5;
titleLayer.alignmentMode = kCAAlignmentCenter;
titleLayer.frame = CGRectMake(0, 50, videoSize.width, videoSize.height / 6);
[parentLayer addSublayer:titleLayer];
//create the composition and add the instructions to insert the layer:
AVMutableVideoComposition* videoComp = [AVMutableVideoComposition videoComposition];
videoComp.renderSize = videoSize;
videoComp.frameDuration = CMTimeMake(1, 30);
videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
/// instruction
AVMutableVideoCompositionInstruction* instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [mixComposition duration]);
AVAssetTrack* mixVideoTrack = [[mixComposition tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableVideoCompositionLayerInstruction* layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mixVideoTrack];
instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
videoComp.instructions = [NSArray arrayWithObject: instruction];
// export video
_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality];
_assetExport.videoComposition = videoComp;
NSLog (@"created exporter. supportedFileTypes: %@", _assetExport.supportedFileTypes);
NSString* videoName = @"NewWatermarkedVideo.mov";
NSString* exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:videoName];
NSURL* exportUrl = [NSURL fileURLWithPath:exportPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:exportPath])
[[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil];
_assetExport.outputFileType = AVFileTypeQuickTimeMovie;
_assetExport.outputURL = exportUrl;
_assetExport.shouldOptimizeForNetworkUse = YES;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
 
//Final code
 
switch (_assetExport.status)
{
case AVAssetExportSessionStatusUnknown:
NSLog(@"Unknown");
break;
case AVAssetExportSessionStatusWaiting:
NSLog(@"Waiting");
break;
case AVAssetExportSessionStatusExporting:
NSLog(@"Exporting");
break;
case AVAssetExportSessionStatusCompleted:
NSLog(@"Created new water mark image");
_playButton.hidden = NO;
break;
case AVAssetExportSessionStatusFailed:
NSLog(@"Failed- %@", _assetExport.error);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Cancelled");
break;
}
}
];   
}

You can download the sample app from github.

Thursday, October 9, 2014

Document Directory path in iOS 8




Problem-

You may have noticed that iOS8 simulator is not visible when you go to the given path-

 Users/Library/Application Support/iPhone Simulator/ 





Solution-

Now in XCode6, data directories are per-devices rather than per-version.

To find the document directory for Xcode6 & iOS8 is not as easy as it was earlier. You have to play guessing game twice. Once for finding the appropriate device. Once you find the device you have to search the application. 

You can find the document directory in the given path.

Library/Developer/CoreSimulator/Devices/cryptic number/data/Containers/Data/Application/cryptic number

Steps to Find Document Directory-

1) Follow the given path.

Users/Library/Developer/CoreSimulator/Devices/ 

2) Now, Device folder will have some cryptic number folders. Each folder will have Data folder & device.plist. Check the devicePlist to know about the deviceType.






3) Once you find your device, you have to follow the given path to find the application & document directory.
Data/Containers/Data/Application/cryptic number


4) Now this cryptic number folder will have 3 folders- Documents ( Document directory), Library & temp.




Note- As finding the document directory path become tedious. So, if you are testing the application then you can check the document directory path programaticaly.
NSLog(@"Documents Directory: %@", [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]);




Wednesday, October 8, 2014

How to update location in iOS 8?

Problem- 

In iOS 8 you will face the issue that location manager delegates unable to get callback when the location is updating if you are using the given code snippet for getting location updates.

  _locationManager = [[CLLocationManager alloc] init];
  
  _locationManager.delegate = self;
  _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
  
  [_locationManager startUpdatingLocation]; 


Solution-

In iOS 8 you have to call requestWhenInUseAuthorization or requestAlwaysAuthorization method before calling startUpdatingLocation methods.

  _locationManager = [[CLLocationManager alloc] init];
  
  _locationManager.delegate = self;
  _locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters;
  
  if(IS_OS_8_OR_LATER)
   [_locationManager requestWhenInUseAuthorization];
  
  [_locationManager startUpdatingLocation]; 

Also, you have to add NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription key in the plist.

If you did’t specify the key into the plist then requestAlwaysAuthorization method will do nothing, as your app should be assumed not to support Always authorization. 

If you always wants to use the locations update even when the app is in background then you have to call requestAlwaysAuthorization & specify NSLocationAlwaysUsageDescription key in the plist. 

In other cases where you don’t want to call location method update always, you can use requestWhenInUseAuthorization & specify NSLocationWhenInUseUsageDescription key in the plist.


Thursday, September 25, 2014

CocoaPods

Cocoapods is the dependency manager tool to manage library dependencies in Objective C projects. It will fetch library source code, resolve dependencies between libraries and create, maintain the right environment to build the project with minimum hassle.

CocoaPods can download code from Github & copy it to your project. You don't need to do this manually.

Basically, CocoaPods is built with Ruby and installable with default Ruby in OSX.

Following are the steps to install cocoapods-

1) Update the RubyGems
$ sudo gem update --system

2) Write this command in terminal to install the gem-
$ sudo gem install cocoapods


Note- During this process RubyGems might ask you if you want to overwrite the rake executable. This warning is raised because the rake gem will be updated as part of this process. Simply confirm by typing y.

3) Setup the cocoapods
$ pod setup

Installing the dependency-

1) Create the empty project & open it in terminal or open the existing project in terminal.

$ cd <pojectpath>

2) Create pod file. This pod file will include all the dependencies for the project.
$ pod init

3) Now,open the pod file & add the library with version number for installation.

target "ProjectName" do

pod 'AFNetworking', '2.2.1' // add this line to pod file to download AFNetworking source code

end


4) Install the pod file. This command will install the dependency for the project & create the workspace. Now you have to use this workspace instead of project file.
$ pod install

Note- If you want to delete the workspace you can use the given command to delete the workspace from the project.
$ rm -rf <workspaceName>