Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - iOS Programming

64 Articles
article-image-understanding-passbook
Packt
15 Jul 2013
5 min read
Save for later

Understanding Passbook

Packt
15 Jul 2013
5 min read
(For more resources related to this topic, see here.) Getting ready With iOS 6, Apple introduced the Passbook app as a central digital wallet for all the store cards, coupons, boarding passes, and event tickets that have become a popular feature of apps. A company wishing to take advantage of this digital wallet and the extra functionality it provides, can use Apple's developer platform to create a Pass for their users. How to do it... To understand Passbook, we need to see a Pass in action. Download the example Pass from: http://passkit.pro/example-generic-pkpass If you open this link within Mobile Safari on an iPhone or iPod Touch running iOS 6, you will be presented with the Pass and the option to add it to your Passbook. Alternatively, you can download the Pass on a Mac or PC and e-mail it to yourself, and then open the e-mail within the Mail app on an iPhone or iPod Touch. Tapping the Pass attachment link will present the Pass. If you choose to add the Pass to your Passbook app, the displayed Pass will disappear, having been filed away within your Passbook. Now click on the home button to return to the home screen and launch the Passbook app. In the app you will now see the Pass that was just added. It contains information specified by the app creator and can be presented when interacting with the company providing the service. Additional information can be placed on the back of the Pass. Tap the i button in the top-right hand corner of the Pass, to reveal the this information. How it works… The following diagram describes how Passes are delivered to a Passbook, and how these can be updated: The process of creating a Pass involves cryptographically signing the Pass using a certificate and key generated from your iOS developer account. For this reason, the generation of the Pass needs to take place on a server, and then be delivered to Passbook either via your own app, as an e-mail attachment, or by embedding it in a website. It's important to note that Apple does not provide any system for the Pass providers to authenticate, validate, or invalidate Passes. The Pass can contain barcode information, but it is up to the Pass provider to provide the infrastructure for reading and processing these barcodes. Instead of just sitting in the Passbook app, waiting to be used, a Pass can contain location and time triggers, that proactively present the Pass to the user, serving as both a reminder and providing convenient access. For example, an event Pass could be set to appear 15 mins before the start time, at the time when a user likely wants to present their event Pass to an attendant. Alternatively, a coupon Pass could be presented as a user approaches their local store where the coupon can be redeemed. Passes that have been added to Passbook can also be updated dynamically. For example, if the Pass is for a store card, a change to the card balance may require an update to the Pass. In the case of, for an airline ticket Pass, a departure gate change should trigger a Pass update. When a Pass needs to be updated, your server sends a push notification to the Passbook app on the user's device. This push notification is not displayed to the user. Upon receiving this Push Notification, the Passbook app then makes a request to your server for the updated Pass information. Your server would then respond to the relevant request, and provide the updated information in the expected format. When the Passbook App on the user's device receives the updated information, it silently updates the Pass. The next time the user looks at the Pass contained in the Passbook app, the updated information is displayed. There's more… Support for Passbook is also built into OSX Mountain Lion (10.8.2). Pass files with the -pkpass file extension will open in a preview window: Clicking on the Add to Passbook button will place the Pass in the Passbook associated with the iCloud account set up in OSX system preferences. The OSX Mail app and Safari also support embedded Passes. When building a Pass, you can specify a relevant time and up to 10 relevant locations that will trigger a message to be displayed on the lock screen. The message looks similar to a push notification, however a Pass notification is less intrusive. When it is relevant to display, it doesn't vibrate the iPhone and it doesn't wake up the screen. The notification only becomes visible when the phone wakes up from sleep. The option to specify relevant time and locations, and how far from the location the notification is triggered, is determined by the Pass type, as we will see later. Apps using Passbook Some of the apps in the App Store using Passbook are as follows : Hotels.com: This uses Passbook for room reservation details. It can be downloaded from http://appstore.com/hotelscom/hotelscom. Starbucks: This uses Passbook for a store card. It can be downloaded from http://appstore.com/starbuckscoffeecompany. Ticketmaster: This uses Passbook for event tickets. It can be downloaded from http://appstore.com/ticketmaster/ticketmaster. United Airlines: This uses Passbook for boarding passes. It can be downloaded from http://appstore.com/unitedairlines. Summary This article introduced you to Passbook. Apple's Passbook feature is a collection of technologies that come together to provide digital wallet functionality to the user. We understood what Passbook consists of, from both the user and Pass creator perspective. Resources for Article : Further resources on this subject: Development of iPhone Applications [Article] iPhone Applications Tune-Up: Design for Performance [Article] New iPad Features in iOS 6 [Article]
Read more
  • 0
  • 0
  • 11159

article-image-geolocation-and-accelerometer-apis
Packt
25 Jan 2012
13 min read
Save for later

Geolocation and Accelerometer APIs

Packt
25 Jan 2012
13 min read
(For more resources on iOS, see here.) The iOS family makes use of many onboard sensors including the three-axis accelerometer, digital compass, camera, microphone, and global positioning system (GPS). Their inclusion has created a world of opportunity for developers, and has resulted in a slew of innovative, creative, and fun apps that have contributed to the overwhelming success of the App Store. Determining your current location The iOS family of devices are location-aware, allowing your approximate geographic position to be determined. How this is achieved depends on the hardware present in the device. For example, the original iPhone, all models of the iPod touch, and Wi-Fi-only iPads use Wi-Fi network triangulation to provide location information. The remaining devices can more accurately calculate their position using an on-board GPS chip or cell-phone tower triangulation. The AIR SDK provides a layer of abstraction that allows you to extract location information in a hardware-independent manner, meaning you can access the information on any iOS device using the same code. This recipe will take you through the steps required to determine your current location. Getting ready An FLA has been provided as a starting point for this recipe. From Flash Professional, open chapter9recipe1recipe.fla from the code bundle which can be downloaded from http://www.packtpub.com/support.   How to do it... Perform the following steps to listen for and display geolocation data: Create a document class and name it Main. Import the following classes and add a member variable of type Geolocation: package { import flash.display.MovieClip; import flash.events.GeolocationEvent; import flash.sensors.Geolocation; public class Main extends MovieClip { private var geo:Geolocation; public function Main() { // constructor code } }}   Within the class' constructor, instantiate a Geolocation object and listen for updates from it: public function Main() { if(Geolocation.isSupported) { geo = new Geolocation(); geo.setRequestedUpdateInterval(1000); geo.addEventListener(GeolocationEvent.UPDATE, geoUpdated); }} Now, write an event handler that will obtain the updated geolocation data and populate the dynamic text fields with it: private function geoUpdated(e:GeolocationEvent):void { latitudeField.text = e.latitude.toString(); longitudeField.text = e.longitude.toString(); altitudeField.text = e.altitude.toString(); hAccuracyField.text = e.horizontalAccuracy.toString(); vAccuracyField.text = e.verticalAccuracy.toString(); timestampField.text = e.timestamp.toString();} Save the class file as Main.as within the same folder as the FLA. Move back to the FLA and save it too. Publish and test the app on your device. When launched for the first time, a native iOS dialog will appear. Tap the OK button to grant your app access to the device's location data.     Devices running iOS 4 and above will remember your choice, while devices running older versions of iOS will prompt you each time the app is launched.   The location data will be shown on screen and periodically updated. Take your device on the move and you will see changes in the data as your geographical location changes. How it works... AIR provides the Geolocation class in the flash.sensors package, allowing the location data to be retrieved from your device. To access the data, create a Geolocation instance and listen for it dispatching GeolocationEvent.UPDATE events. We did this within our document class' constructor, using the geo member variable to hold a reference to the object: geo = new Geolocation();geo.setRequestedUpdateInterval(1000);geo.addEventListener(GeolocationEvent.UPDATE, geoUpdated); The frequency with which location data is retrieved can be set by calling the Geolocation. setRequestedUpdateInterval() method. You can see this in the earlier code where we requested an update interval of 1000 milliseconds. This only acts as a hint to the device, meaning the actual time between updates may be greater or smaller than your request. Omitting this call will result in the device using a default update interval. The default interval can be anything ranging from milliseconds to seconds depending on the device's hardware capabilities. Each UPDATE event dispatches a GeolocationEvent object, which contains properties describing your current location. Our geoUpdated() method handles this event by outputting several of the properties to the dynamic text fields sitting on the stage: private function geoUpdated(e:GeolocationEvent):void { latitudeField.text = e.latitude.toString(); longitudeField.text = e.longitude.toString(); altitudeField.text = e.altitude.toString(); hAccuracyField.text = e.horizontalAccuracy.toString(); vAccuracyField.text = e.verticalAccuracy.toString(); timestampField.text = e.timestamp.toString();} The following information was output: Latitude and longitude Altitude Horizontal and vertical accuracy Timestamp The latitude and longitude positions are used to identify your geographical location. Your altitude is also obtained and is measured in meters. As you move with the device, these values will update to reflect your new location. The accuracy of the location data is also shown and depends on the hardware capabilities of the device. Both the horizontal and vertical accuracy are measured in meters. Finally, a timestamp is associated with every GeolocationEvent object that is dispatched, allowing you to determine the actual time interval between each. The timestamp specifies the milliseconds that have passed since the app was launched. Some older devices that do not include a GPS unit only dispatch UPDATE events occasionally. Initially, one or two UPDATE events are dispatched, with additional events only being dispatched when location information changes noticeably. Also note the use of the static Geolocation.isSupported property within the constructor. Although this will currently return true for all iOS devices, it cannot be guaranteed for future devices. Checking for geolocation support is also advisable when writing cross-platform code. For more information, perform a search for flash.sensors.Geolocation and flash. events.GeolocationEvent within Adobe Community Help. There's more... The amount of information made available and the accuracy of that information depends on the capabilities of the device. Accuracy The accuracy of the location data depends on the method employed by the device to calculate your position. Typically, iOS devices with an on-board GPS chip will have a benefit over those that rely on Wi-Fi triangulation. For example, running this recipe's app on an iPhone 4, which contains a GPS unit, results in a horizontal accuracy of around 10 meters. The same app running on a third-generation iPod touch and relying on a Wi-Fi network, reports a horizontal accuracy of around 100 meters. Quite a difference! Altitude support The current altitude can only be obtained from GPS-enabled devices. On devices without a GPS unit, the GeolocationEvent.verticalAccuracy property will return -1 and GeolocationEvent.altitude will return 0. A vertical accuracy of -1 indicates that altitude cannot be detected. You should be aware of, and code for these restrictions when developing apps that provide location-based services. Do not make assumptions about a device's capabilities. If your application relies on the presence of GPS hardware, then it is possible to state this within your application descriptor file. Doing so will prevent users without the necessary hardware from downloading your app from the App Store. Mapping your location The most obvious use for the retrieval of geolocation data is mapping. Typically, an app will obtain a geographic location and display a map of its surrounding area. There are several ways to achieve this, but launching and passing location data to the device's native maps application is possibly the easiest solution. If you would prefer an ActionScript solution, then there is the UMap ActionScript 3.0 API, which integrates with map data from a wide range of providers including Bing, Google, and Yahoo!. You can sign up and download the API from www.umapper.com. Calculating distance between geolocations When the geographic coordinates of two separate locations are known, it is possible to determine the distance between them. AIR does not provide an API for this but an AS3 solution can be found on the Adobe Developer Connection website at: http://cookbooks.adobe.com/index.cfm?event=showdetails&postId=5701. The UMap ActionScript 3.0 API can also be used to calculate distances. Refer to www.umapper.com. Geocoding Mapping providers, such as Google and Yahoo!, provide geocoding and reverse-geocoding web services. Geocoding is the process of finding the latitude and longitude of an address, whereas reverse-geocoding converts a latitude-longitude pair into a readable address. You can make HTTP requests from your AIR for iOS application to any of these services. As an example, take a look at the Yahoo! PlaceFinder web service at http://developer.yahoo.com/geo/placefinder. Alternatively, the UMap ActionScript 3.0 API integrates with many of these services to provide geocoding functionality directly within your Flash projects. Refer to the uMapper website. Gyroscope support Another popular sensor is the gyroscope, which is found in more recent iOS devices. While the AIR SDK does not directly support gyroscope access, Adobe has made available a native extension for AIR 3.0, which provides a Gyroscope ActionScript class. A download link and usage examples can be found on the Adobe Developer Connection site at www.adobe.com/devnet/air/native-extensions-for-air/extensions/gyroscope.html. Determining your speed and heading The availability of an on-board GPS unit makes it possible to determine your speed and heading. In this recipe, we will write a simple app that uses the Geolocation class to obtain and use this information. In addition, we will add compass functionality by utilizing the user's current heading. Getting ready You will need a GPS-enabled iOS device. The iPhone has featured an on-board GPS unit since the release of the 3G. GPS hardware can also be found in all cellular network-enabled iPads. From Flash Professional, open chapter9recipe2recipe.fla from the code bundle. Sitting on the stage are three dynamic text fields. The first two (speed1Field and speed2Field) will be used to display the current speed in meters per second and miles per hour respectively. We will write the device's current heading into the third—headingField. Also, a movie clip named compass has been positioned near the bottom of the stage and represents a compass with north, south, east, and west clearly marked on it. We will update the rotation of this clip in response to heading changes to ensure that it always points towards true north. How to do it... To obtain the device's speed and heading, carry out the following steps: Create a document class and name it Main. Add the necessary import statements, a constant, and a member variable of type Geolocation: package { import flash.display.MovieClip; import flash.events.GeolocationEvent; import flash.sensors.Geolocation; public class Main extends MovieClip { private const CONVERSION_FACTOR:Number = 2.237; private var geo:Geolocation; public function Main() { // constructor code } }} Within the constructor, instantiate a Geolocation object and listen for updates: public function Main() { if(Geolocation.isSupported) { geo = new Geolocation(); geo.setRequestedUpdateInterval(50); geo.addEventListener(GeolocationEvent.UPDATE, geoUpdated); }} We will need an event listener for the Geolocation object's UPDATE event. This is where we will obtain and display the current speed and heading, and also update the compass movie clip to ensure it points towards true north. Add the following method: private function geoUpdated(e:GeolocationEvent):void { var metersPerSecond:Number = e.speed; var milesPerHour:uint = getMilesPerHour(metersPerSecond); speed1Field.text = String(metersPerSecond); speed2Field.text = String(milesPerHour); var heading:Number = e.heading; compass.rotation = 360 - heading; headingField.text = String(heading);} Finally, add this support method to convert meters per second to miles per hour: private function getMilesPerHour(metersPerSecond:Number):uint { return metersPerSecond * CONVERSION_FACTOR;} Save the class file as Main.as. Move back to the FLA and save it too. Compile the FLA and deploy the IPA to your device. Launch the app. When prompted, grant your app access to the GPS unit. Hold the device in front of you and start turning on the spot. The heading (degrees) field will update to show the direction you are facing. The compass movie clip will also update, showing you where true north is in relation to your current heading. Take your device outside and start walking, or better still, start running. On average every 50 milliseconds you will see the top two text fields update and show your current speed, measured in both meters per second and miles per hour. How it works... In this recipe, we created a Geolocation object and listened for it dispatching UPDATE events. An update interval of 50 milliseconds was specified in an attempt to receive the speed and heading information frequently. Both the speed and heading information are obtained from the GeolocationEvent object, which is dispatched on each UPDATE event. The event is captured and handled by our geoUpdated() handler, which displays the speed and heading information from the accelerometer. The current speed is measured in meters per second and is obtained by querying the GeolocationEvent.speed property. Our handler also converts the speed to miles per hour before displaying each value within the appropriate text field. The following code does this: var metersPerSecond:Number = e.speed;var milesPerHour:uint = getMilesPerHour(metersPerSecond);speed1Field.text = String(metersPerSecond);speed2Field.text = String(milesPerHour); The heading, which represents the direction of movement (with respect to true north) in degrees, is retrieved from the GeolocationEvent.heading property. The value is used to set the rotation property of the compass movie clip and is also written to the headingField text field: var heading:Number = e.heading;compass.rotation = 360 - heading;headingField.text = String(heading); The remaining method is getMilesPerHour() and is used within geoUpdated() to convert the current speed from meters per second into miles per hour. Notice the use of the CONVERSION_FACTOR constant that was declared within your document class: private function getMilesPerHour(metersPerSecond:Number):uint { return metersPerSecond * CONVERSION_FACTOR;} Although the speed and heading obtained from the GPS unit will suffice for most applications, the accuracy can vary across devices. Your surroundings can also have an affect; moving through streets with tall buildings or under tree coverage can impair the readings. You can find more information regarding flash.sensors.Geolocation and flash.events.GeolocationEvent within Adobe Community Help. There's more... The following information provides some additional detail. Determining support Your current speed and heading can only be determined by devices that possess a GPS receiver. Although you can install this recipe's app on any iOS device, you won't receive valid readings from any model of iPod touch, the original iPhone, or W-Fi-only iPads. Instead the GeolocationEvent.speed property will return -1 and GeolocationEvent.heading will return NaN. If your application relies on the presence of GPS hardware, then it is possible to state this within the application descriptor file. Doing so will prevent users without the necessary hardware from downloading your app from the App Store. Simulating the GPS receiver During the development lifecycle it is not feasible to continually test your app in a live environment. Instead you will probably want to record live data from your device and re-use it during testing. There are various apps available that will log data from the sensors on your device. One such app is xSensor, which can be downloaded from iTunes or the App Store and is free. Its data sensor log is limited to 5KB but this restriction can be lifted by purchasing xSensor Pro. Preventing screen idle Many of this article's apps don't require you to touch the screen that often. Therefore you will be likely to experience the backlight dimming or the screen locking while testing them. This can be inconvenient and can be prevented by disabling screen locking.  
Read more
  • 0
  • 0
  • 11012

article-image-using-storyboards
Packt
14 Jun 2013
7 min read
Save for later

Using Storyboards

Packt
14 Jun 2013
7 min read
(For more resources related to this topic, see here.) Configuring storyboards for a project Getting ready In this recipe, we will learn how to configure an application's project properties using Xcode so that it is set up correctly to use a storyboard file. How to do it... To begin, perform the following simple steps: Select your project from the project navigator window. Then, select your project target from under the TARGETS group and select the Summary tab. Select MainStoryboard from the Main Storyboard drop-down menu, as shown in the preceding screenshot. How it works... In this recipe, we gained an understanding of what storyboards are, as well as how they differ from user interfaces created in the past, whereby a new view would need to be created for each XIB file for your application. Whether you are creating applications for the iPad or iPhone, each view controller that gets created within your storyboard represents the contents of a single screen, comprised of the contents of more than one scene. Each object contained within a view controller can be linked to another view controller that implements another scene. In our final steps, we looked at how to configure our project properties so that it is set up to use the storyboard user interface file by our application. There's more… You can also choose to manually add new Storyboard template to your project. This can be achieved by performing the following simple steps: Select your project from the project navigator window. Select File New | File…| or press command + N. Select the Storyboard template from the list of available templates, located under the User Interface subsection within the iOS section. Click on the Next button to proceed to the next step in the wizard. Ensure that you have selected iPhone from under the Device Family drop-down menu. Click on the Next button to proceed to the next step in the wizard. Specify the name of the storyboard file within the Save As field as the name of the file to be created. Click on the Create button to save the file to the specified folder. Finally, when we create our project using storyboards, we will need to modify our application's delegate AppDelegate.m file, as shown in the following code snippet: - (BOOL)application:(UIApplication *)application didFinishLaunchin gWithOptions:(NSDictionary *)launchOptions { // Override point for customization after // application launch. return YES; } For more information about using storyboards in your applications, you can refer to the Apple Developer documentation, located at https://developer.apple.com/library/ios/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/InterfaceBuilder/InterfaceBuilder. Creating a Twitter application In this recipe, we will learn how to create a single view application to build our Twitter application. Getting ready In this recipe, we will start by creating our TwitterExample project. How to do it... To begin with creating a new Xcode project, perform the following simple steps: Launch Xcode from the /Developer/Applications folder. Select Create a new Xcode project, or click on File | New | Project…. Select Single View Application from the list of available templates. Click on the Next button to proceed to the next step in the wizard. Next, enter in TwitterExample as the name of your project. Select iPhone from under the Devices drop-down menu. Ensure that the Use Storyboards checkbox has been checked. Ensure that the Use Automatic Reference Counting checkbox has been checked. Ensure that the Include Unit Tests checkbox has not been checked. Click on the Next button to proceed to the next step in the wizard. Specify the location where you would like to save your project. Then, click on the Create button to save your project at the specified location. The Company Identifier for your app needs to be unique. Apple recommends that you use the reverse domain style (for example, com.domainName.appName). Once your project has been created, you will be presented with the Xcode development environment, along with the project files that the template created for you. How it works... In this recipe, we just created an application that contains a storyboard and consists of one view controller, which does not provide any functionality at the moment. In the following recipes, we will look at how we can add functionality to view controllers, create storyboard scenes, and transition between them. Creating storyboard scenes The process of creating scenes involves adding a new view controller to the storyboard, where each view controller is responsible for managing a single scene. A better way to describe scenes would be to think of a movie reel, where each frame that is being displayed is the actual scene that connects onto the next part. Getting ready When adding scenes to your storyboard file, you can add controls and views to the view controller's view, just as you would do for an XIB file, and have the ability to configure outlets and actions between your view controllers and its views. How to do it... To add a new scene into your storyboard file, perform the following simple steps: From the project navigator, select the file named MainStoryboard.storyboard. From Object Library, select and drag a new View Controller object on to the storyboard canvas. This is shown in the following screenshot: Next, drag a Label control on to the view and change the label's text property to read About Twitter App. Next, drag a Round Rect Button control on to the view that we will use in a later section to call the calling view. In the button's attributes, change the text to read Go Back. Next, on the first view controller, drag a Round Rect Button control on to the view. In the button's attributes, change the text to read About Twitter App. This will be used to call the new view that we added in the previous step. Next, on the first view controller, drag a Round Rect Button control on to the view, underneath the About Twitter App button that we created in the previous step. In the button's attributes, change the text to read Compose Tweet. Next, save your project by selecting File | Save from the menu bar, or alternatively by pressing command + S. Once you have added the controls to each of the view, your final interface should look something like what is shown in the following screenshot: The next step is to create the Action event for our Compose Tweet button so that it has the ability to post tweets. To create an action, perform the following steps: Open the assistant editor by selecting Navigate | Open In Assistant Editor or by pressing option + command + ,. Ensure that the ViewController.h interface file gets displayed. Select the Compose Tweet button; hold down the control key, and drag it from the Compose Tweet button to the ViewController.h interface file between the @interface and @end tags. Choose Action from the Connection drop-down menu for the connection to be created. Enter composeTweet for the name of the method to create. Choose UIButton from the Type drop-down menu for the type of method to create. The highlighted line in the following code snippet shows the completed ViewController.h interface file, with our method that will be responsible for calling and displaying our tweet sheet. // ViewController.h // TwitterExample // // Created by Steven F Daniel on 21/09/12. // Copyright (c) 2012 GenieSoft Studios. All rights reserved. #import @interface ViewController : UIViewController // Create the action methods - (IBAction)composeTweet:(UIButton *)sender; @end Now that we have created our scene, buttons, and actions, our next step is to configure the scene, which is shown in the next recipe. How it works... In this recipe, we looked at how we can add a new view controller to our storyboard and then started to add controls to each of our view controllers and customize their properties. Next, we looked at how we can create an Action event for our Compose Tweet button that will be responsible for responding and executing the associated code behind it to display our tweet sheet. Instead of us hooking up an event handler to the TouchUpInside event of the button, we decided to simply add an action to it and handle the output of this ourselves. These types of actions are called "instance methods". Here we are basically creating the Action method that will be responsible for allowing the user to compose and send a Twitter message.
Read more
  • 0
  • 0
  • 10518

article-image-evenly-spaced-views-auto-layout-ios
Joe Masilotti
16 Apr 2015
5 min read
Save for later

Evenly Spaced Views with Auto Layout in iOS

Joe Masilotti
16 Apr 2015
5 min read
When the iPhone first came out there was only one screen size to worry about 320, 480. Then the Retina screen was introduced doubling the screen's resolution. Apple quickly introduced the iPhone 5 and added an extra 88 points to the bottom. With the most recent line of iPhones two more sizes were added to the mix. Before even mentioning the iPad line that is already five different combinations of heights and widths to account for. To help remedy this growing number of sizes and resolutions Apple introduced Auto Layout with iOS 6. Auto Layout is a dynamic way of laying out views with constraints and rules to let the content fit on multiple screen sizes; think "responsive" for mobile. Lots of layouts are possible with Auto Layout but some require an extra bit of work. One of the more common, albeit tricky, arrangements is to have evenly spaced elements. Having the view scale up to different resolutions and look great on all devices isn't hard and can be done in both Interface Builder or manually in code. Let's walk through how to evenly space views with Auto Layout using Xcode's Interface Builder. Using Interface Builder The easiest way to play around and test layout in IB is to create a new Single View Application iOS project.   Open Main.storyboard and select ViewController on the left. Don't worry that it is showing a square view since we will be laying everything out dynamically. The first addition to the view will be the three `UIView`s we will be evenly spacing. Add them along the view from left to right and assign different colors to each. This will make it easier to distinguish them later. Don't worry about where they are we will fix the layout soon enough.   Spacer View Layout Ideally we would be able to add constraints that evenly space these out directly. Unfortunately, you can not set *equals* restrictions on constraints, only on views. What that means is we have to create spacer views in between our content and then set equal constraints on those. Add four more views, one between the edges and the content views.   Before we add our first constraint let's name each view so we can have a little more context when adding their attributes. One of the most frustrating things when working with Auto Layout is seeing the little red arrow telling you something is wrong. Let's try and incrementally add constraints and get back to a working state as quickly as possible. The first item we want to add will constrain the Left Content view using the spacer. Select the Left Spacer and add left 20, top 20, and bottom 20 constraints.   To fix this first error we need to assign a width to the spacer. While we will be removing it later it makes sense to always have a clean slate when moving on to another view. Add in a width (50) constraint and let IB automatically and update its frame.   Now do the same thing to the Right Spacer.   Content View Layout We will remove the width constraints when everything else is working correctly. Consider them temporary placeholders for now. Next lets lay out the Left Content view. Add a left 0, top 20, bottom 20, width 20 constraint to it.   Follow the same method on the Right Content view.   Twice more follow the same procedure for the Middle Spacer Views giving them left/right 0, top 20, bottom 20, width 50 constraints.   Finally, let's constrain the Middle Content view. Add left 0, top 20, right 0, bottom 20 constraints to it and lay it out.   Final Constraints Remember when I said it was tricky? Maybe a better way to describe this process is long and tedious. All of the setup we have done so far was to set us up in a good position to give the constraints we actually want. If you look at the view it doesn't look very special and it won't even resize the right way yet. To start fix this we bring in the magic constraint of this entire example, Equal Widths on the spacer views. Go ahead and delete the four explicit Width constraints on the spacer views and add an Equal Width constraint to each. Select them all at the same time then add the constraint so they work off of each other.   Finally, set explicit widths on the three content views. This is where you can start customizing the layout to have it look the way you want. For my view I want the three views to be 75 points wide so I removed all of the Width constraints and added them back in for each. Now set the background color of the four spacer views to clear and hide them. Running the app on different size simulators will produce the same result: the three content views remain the same width and stay evenly spaced out along the screen. Even when you rotate the device the views remain spaced out correctly.   Try playing around with different explicit widths of the content views. The same technique can be used to create very dynamic layouts for a variety of applications. For example, this procedurecan be used to create a table cell with an image on the left, text in the middle, and a button on the right. Or it can make one row in a calculator that sizes to fit the screen of the device. What are you using it for? About the author Joe Masilotti is a test-driven iOS developer living in Brooklyn, NY. He contributes to open-source testing tools on GitHub and talks about development, cooking, and craft beer on Twitter.
Read more
  • 0
  • 0
  • 10436

article-image-getting-ready-rubymotion
Packt
22 Aug 2013
13 min read
Save for later

Getting Ready for RubyMotion

Packt
22 Aug 2013
13 min read
(For more resources related to this topic, see here.) How can I develop an iOS application? To develop iOS applications, there are various third-party frameworks available, apart from Apple libraries. If we broadly categorize the ways in which we can create iOS applications, we can divide them into three ways. Native apps using Objective-C This is the most standard way to build your application, by interacting with Apple APIs and writing apps in Objective-C. Applications made using native Apple APIs can use all possible device capabilities, and are relatively more reliable and high performing (however, the topic of performance is debatable based on the quality of the developer's code). Mobile web applications Mobile web applications are simple web applications extended for mobile web browsers, which can be created using standard web technologies such as HTML5. For example, if we browse through http://www.twitter.com in a mobile browser, it will be redirected to http://mobile.twitter.com, which renders its corresponding views for mobile devices. These applications are easy to create but the downside is that they have limited access to user data (for example, phonebook) and hardware (for example, camera). Hybrid applications These applications are somewhere in between mobile web apps and native applications. They are created using common web technologies such as HTML5 and JavaScript and have the ability to use device capabilities via their homegrown APIs. Some of the popular hybrid frameworks include Rhomobile and Phonegap. If we compare the speed of development and user experience, it can be summed up with the following diagrams: From the preceding diagrams we see that mobile web apps can be created very quickly but we have to compromise on user experience. While native apps using Objective-C have good user experience, they have a very steep initial learning curve for web developers. RubyMotion is good news for both users and developers. Users get an amazing experience of a native application and developers are able to develop applications rapidly in comparison to applications developed using Objective-C. Let's now learn about RubyMotion. What is RubyMotion? RubyMotion is a toolchain that allows developers to develop native iOS applications using the Ruby programming language. RubyMotion acts as a compiler that interacts with the iOS SDK(Software Development Kit). This gives us enormous power to make use of Apple libraries; therefore, once the application has compiled and loaded, the device has no idea whether it's an application made using Objective-C or RubyMotion. RubyMotion is a product of HipByte, founded by Laurent Sansonetti. While developing applications with RubyMotion using Ruby, you always have access to the iOS SDK classes. This gives you the benefit of even mixing Objective-C and Ruby code, as RubyMotion implements Ruby on top of the Objective-C runtime and iOS Foundation classes. This is how a typical RubyMotion application works. The code written in RubyMotion is fully compiled into machine code, so the application created by RubyMotion is as fast as the one created using Objective-C. Why RubyMotion? So far we have learned what RubyMotion is, but the question that comes to mind is, why should we use RubyMotion? There are many reasons why RubyMotion is a good choice for building robust iOS apps. The following sections detail a few that we think matter the most. If you are not an Objective-C fan For a newbie developer, Objective-C is an arduous affair. It's complicated to code; even for doing a simple thing, we have to write many lines of code. Though it is a powerful language and one of the best object-oriented ones available, it is time consuming and the learning curve is very steep. On the other hand, Ruby is more expressive, simple, and productive in comparison to Objective-C. Because of its simplicity, developers can shift their focus onto problem solving rather than spending time on trivial stuff, which is taken care by Ruby itself. In short, we can say RubyMotion allows us to use the power of Objective-C with the simplicity of Ruby. Ruby classes used in RubyMotion are inherited from Objective-C classes. If you are familiar with the concept of object-oriented programming, you can understand its power. This means we can directly use Apple iOS SDK classes from your RubyMotion code. It is not a bridge RubyMotion apps get direct access to iOS SDK APIs, which means the size of application and performance created using RubyMotion is comparable to the one created using Objective-C. It implements Ruby on top of the Objective-C runtime and iOS Foundation classes. RubyMotion uses a state-of-the-art static compiler based on Low Level Virtual Machine (LLVM), which converts the Ruby source code into a blazing fast machine code. The original source code is never present in the application bundle. A typical application weighs less than 1 MB, but the size can increase depending on the use case. Managed memory One of the key features of RubyMotion is that it takes care of memory management. Just like ARC (Automatic Reference Counting) with Xcode 4.4 and above, we don't have to take the pain of releasing the memory once an object is no longer used. RubyMotion does the magic and we don't need to think about it. It handles it on its own. Terminal-based workflow RubyMotion has a terminal-based workflow; from creation of the application to deployment, everything can be done through terminals. If you are used to working on terminals, you know it adds to speedier development. Easy debugging with REPL The terminal window where you run Rake also gives you the option to debug with REPL (Read Evaluate Print Loop), which lets you use Ruby expressions that are evaluated on the spot, and the results are reflected on the simulator while the application is still running. The ability to make live changes to the user interface and internal application data structures at runtime is extremely useful for testing and troubleshooting issues with the application, as this saves a lot of time and is much faster than a traditional edit-compile-run loop. It is extendable We can use RubyMotion salted gems easily by just adding them in the Rakefile. What are RubyMotion salted gems? We can't use all the gems that are available for Ruby right now, but there are a lot of gems specifically developed for RubyMotion. As the RubyMotion developer community expands, so will its gem bouquet, and this will make our application development rapid. Third-party Objective-C libraries can be easily used in a RubyMotion project. It supports CocoaPods, which is a dependency manager for Objective-C libraries, making this process a bit easier. Debugging and testing RubyMotion has a console-based inbuilt interactive debugger for troubleshooting the issues both on a simulator and on a device using GDB (GNU Debugger). GDB is extremely powerful on its own, and RubyMotion uses it for debugging the compiled Ruby code. Also, RubyMotion projects are fit for Test Driven Development (TDD). We can write a unit test for our code from the beginning. We can use Behavior Driven Development (BDD) with RubyMotion, which is integrated into every project. Pop quiz Q.1.How can we distinguish between the iOS application created by RubyMotion and the iOS application created by Objective-C? You can distinguish based on the user experience of the application. You can distinguish based on the performance of the application. You can't distinguish based on the user experience and performance of the application. Solution: If your answer was option 3, you were right. We can't distinguish between applications created by RubyMotion or Objective-C as the user experience and performance are similar. Q.2. How can we extend RubyMotion? We can use Objective-C libraries. We can use all Ruby gems. We can use RubyMotion-flavored gems. We can't use any other libraries. Solution: If your answer was option 1 and 3, you were right. Yes, we can use Objective-C libraries and also RubyMotion-flavored gems. RubyMotion installation – furnish your environment Now that we have got a good introduction to RubyMotion, let's set up our development environment; but before that let's run through some of the prerequisites. Prerequisites for RubyMotion You need a Mac OS: we can't develop iOS applications with RubyMotion on any other operating system; so we definitely need a Mac OS. OSX 10.6 or higher: RubyMotion requires a Mac running OSX 10.6 or higher. OSX 10.7 Lion is highly recommended. Ruby: the Ruby framework comes preinstalled with Mac OS X. If you have multiple versions of Ruby, we recommend that you use Ruby Version Manager (RVM). For more details, visit https://rvm.io/. Xcode: next we need to install Xcode, which includes the iOS SDK, developed by Apple and essential for developing iOS applications. It can be downloaded from the App Store for free. It also includes the iPhone/iPad simulator, which will be used for testing our application. Command Line Tools: after installing the Xcode toolchain, we need to install the command-line tools package, which is necessary for RubyMotion. To confirm that command-line tools is installed with your Xcode, open Xcode in your Applications folder, go to the Preferences window, and click on the Downloads tab. You should see the Command Line Tools package in this list. If it is not yet installed, make sure to click on the Install button. If you have an old version of Xcode, run the following command on the terminal: sudo xcode-select -switch /Applications/Xcode.app/Contents/Developer This command will set up the default Xcode path. Installing RubyMotion RubyMotion installation is really simple and takes no time at all. RubyMotion is a commercial product that you need to purchase from www.rubymotion.com. Once purchased, you will receive your unique license key and installer. RubyMotion installation is a five-step procedure and is given here: Once you have received the package, run the RubyMotion installer as follows: Read and accept the EULA (End User License Agreement). Enter the license number you have received as shown in the following screenshot: Time for a short break—it will take a few minutes for RubyMotion to get downloaded and installed on your system. You can relax for some time. Yippee!! There is no step 5. And that's how quick it is to start working with RubyMotion. Update RubyMotion RubyMotion is a fast-moving framework and we need to upgrade it once there is a new release available. Upgrading RubyMotion is again really simple—with one command, you can easily upgrade it to the latest version. sudo motion update You need to be connected to the Internet for an upgrade to happen. If you want to work on an old version, you can downgrade using the following command: sudo motion update –force-version=1.2 But we recommend using the latest version. How do we check we've done everything correctly? Now that we have installed our RubyMotion copy, it's good practice to confirm which version we have installed; to do this, go to the terminal and run the following: motion –v This command outputs the RubyMotion version installed on your machine. If you get an error, you need to reinstall. Pick your own editor – you are not forced to use Xcode With RubyMotion, you are not forced to use Xcode. As every developer is more comfortable with a specific editor, you are open to choose what you like. However, we recommend the following editors for Ruby development: RubyMine Vim TextMate Sublime Emacs RubyMine now provides full support to a RubyMotion project. How to get help If you are facing some issues, the preferred way to get a solution is to discuss it at the RubyMotion Google group, (https://groups.google.com/forum/?fromgroups#!forum/rubymotion), where you can interact with fellow developers from the community and get a speedy resolution. Sometimes you might not get a precise response from the RubyMotion group. Not to worry, RubyMotion support is there to rescue you. If you have a feature request, an issue, or simply want to ask a question, you can log a support ticket—that too from the command line using the following command: $ motion support This will open up a new window in your browser. You can fill and submit the form with your query. Your RubyMotion license key, email address, and environment details will be added automatically. The RubyMotion community is growing at a very fast pace. In a short span of time, a lot of popular RubyMotion gems have been created by developers. FAQs We believe no question is silly. By now you will have many questions in your mind regarding RubyMotion. We have tried to answer a few of the most frequently asked questions (FAQs) related to topics covered so far in this section. Here are a few of them: Q1. Are the applications created by RubyMotion in keeping with Apple guidelines? Answer. Yes, RubyMotion strongly follows the review guidelines provided by Apple. Many applications created using RubyMotion are already available at the App Store. Q2. Will my RubyMotion application work on a Blackberry, Android, or Windows phone? Answer. No, applications created using RubyMotion are only for iOS devices; it is an alternative to programming in Objective-C. For a single-source multi-device application, we would recommend hybrid frameworks such as Rhomobile, Phonegap, and Titanium. For android development using Ruby, you can try Rubuto. Q3. Can I share an application with someone? Answer. Yes and no. With the Apple Developer Program membership, you can share your application only for testing purposes with a maximum of 100 devices, where each device has to be registered individually with Apple. Also, you cannot distribute your application on the App Store for testing. Once you have finished developing your application and are ready to ship, you can submit it to Apple for an App Store review. Q4. Can I use Ruby gems? Answer. Yes and no. No because we can't use normal Ruby gems, which you generally use in your Ruby on Rails projects; and yes because you can use gems that are specifically developed for RubyMotion, and there are already many such gems. Q5. Will my application work on iPad and iPod Touch? Answer. Absolutely, your application will work on any iOS devices, namely iPhone, iPad, and iPod Touch. Q6 Is Ruby allowed on the App Store? Answer. The App Store can't distinguish between applications made using Objective-C and those made using RubyMotion. So, no worries, our RubyMotion applications are fit for the App Store. Q7. Can I use third-party Objective-C libraries? Answer. Certainly. Third-party Objective-C libraries can be used in your project. RubyMotion provides integration with the CocoaPods dependency manager, which helps in reducing the hassle. You also can use C/C++ code provided that you wrap it into the Objective-C classes and methods. Q8. Is RubyMotion open source? Answer. RubyMotion as a toolchain is open source (available at GitHub). The closed source part is the Ruby runtime, which is, however, very similar to MacRuby runtime (which is open source). Summary Let's review all that we have learned so far. We first discussed the different ways to create iOS applications. Then we started with RubyMotion and discussed why to use it. And in the last section, we learned how to get started with RubyMotion and which editor fits with it. Now that we have our RubyMotion framework up and running, the next obvious task is to create our very first application, the most rudimentary Hello World application. Resources for Article : Further resources on this subject: Introducing RubyMotion and the Hello World app [Article] iPhone Applications Tune-Up: Design for Performance [Article] Introducing Xcode Tools for iPhone Development [Article]
Read more
  • 0
  • 0
  • 10090

article-image-batterymonitor-application
Packt
30 Nov 2012
9 min read
Save for later

BatteryMonitor Application

Packt
30 Nov 2012
9 min read
(For more resources related to this topic, see here.) Overview of the technologies The BatteryMonitor application makes reference to two very important frameworks to allow for drawing of graphics to the iOS device's view, as well as composing and sending of e-mail messages, directly within the application. In this article, we will be making use of the Core Graphics framework that will be responsible for handling the creation of our battery gauge to allow the contents to be filled based on the total amount of battery life remaining on the device. We will then use the MessageUI framework that will be responsible for composing and sending e-mails whenever the application has determined that the battery levels fall below the 20 percent threshold. This is all handled and done directly within our app. We will make use of the UIDevice class that will be used to gather the device information for our iOS device. This class enables you to recover device-specific values, including the model of the iOS device that is being used, the device name, and the OS name and version. We will then use the MFMailComposeViewController class object to directly open up the e-mail dialog box within the application. The information that you can retrieve from the UIDevice class is shown in the following table: Type Description System name This returns the name of the operating system that is currently in use. Since all current generation iOS devices run using the same OS, only one will be displayed; that is iOS 5.1. System version This lists the firmware version that is currently installed on the iOS device; that is, 4.3, 4.31, 5.01, and so on. Unique identifier The unique identifier of the iOS device generates a hexadecimal number to guarantee that it is unique for each iOS device, and does this by applying an internal hash to several of its hardware specifiers, including the device's serial number. This unique identifier is used to register the iOS devices at the iOS portal for provisioning of distribution of software apps. Apple is currently phasing out and rejecting apps that access the Unique Device Identifier on an iOS device to solve issues with piracy, and has suggested that you should create a unique identifier that is specific to your app. Model The iOS model returns a string that describes its platform; that is, iPhone, iPod Touch, and iPad. Name This represents the assigned name of the iOS device that has been assigned by the user within iTunes. This name is also used to create the localhost names for the device, particularly when networking is used. For more information on the UIDevice class, you can refer to the Apple Developer Documentation that can be found and located at the following URL: https://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIDevice_Class/Reference/UIDevice.html. Building the BatteryMonitor application Monitoring battery levels is a common thing that we do in our everyday lives. The battery indicator on the iPhone/iPad lets us know when it is time for us to recharge our iOS device. In this section, we will look at how to create an application that can run on an iOS device to enable us to monitor battery levels on an iOS device, and then send an e-mail alert when the battery levels fall below the threshold. We first need to create our BatteryMonitor project. It is very simple to create this in Xcode. Just follow the steps listed here. Launch Xcode from the /Xcode4/Applications folder. Choose Create a new Xcode project, or File | New Project. Select the Single View Application template from the list of available templates. Select iPad from under the Device Family drop-down list. Ensure that the Use Storyboard checkbox has not been selected. Select the Use Automatic Reference Counting checkbox. Ensure that the Include Unit Tests checkbox has not been selected. Click on the Next button to proceed with the next step in the wizard. Enter in BatteryMonitor as the name for your project. Then click on the Next button to proceed with the next step of the wizard. Specify the location where you would like to save your project. Then, click on the Save button to continue and display the Xcode workspace environment. Now that we have created our BatteryMonitor project, we need to add the MessageUI framework to our project. This will enable us to send e-mail alerts when the battery levels fall below the threshold. Adding the MessageUI framework to the project As we mentioned previously, we need to add the MessageUI framework to our project to allow us to compose and send an e-mail directly within our iOS application, whenever we determine that our device is running below the allowable percentage. To add the MessageUI framework, select Project Navigator Group, and follow the simple steps outlined here: Click and select your project from Project Navigator. Then, select your project target from under the TARGETS group. Select the Build Phases tab. Expand the Link Binary With Libraries disclosure triangle. Finally, use + to add the library you want. Select MessageUI.framework from the list of available frameworks. Now that we have added MessageUI.framework into our project, we need to start building our user interface that will be responsible for allowing us to monitor the battery levels of our iOS device, as well as handle sending out e-mails when the battery levels fall below the agreed threshold. Creating the main application screen The BatteryMonitor application doesn't do anything at this stage; all we have done is created the project and added the MessageUI framework to handle the sending of e-mails when our battery levels are falling below the threshold. We now need to start building the user interface for our BatteryMonitor application. This screen will consist of a View controller, and some controls to handle setting the number of bars to be displayed, as well as whether the monitoring of the battery should be enabled or disabled. Select the ViewController.xib file from Project Navigator. Set the value of Background of the View controller to read Black Color. Next, from Object Library, select-and-drag a (UILabel) Label control, and add this to our view. Modify the Text property of the control to Battery Status:. Modify the Font property of the control to System 42.0. Modify the Alignment property of the control to Center. Next, from Object Library, select-and-drag another (UILabel) Label control, and add this to our view directly underneath the Battery Status label. Modify the Text property of the control to Battery Level:. Modify the Font property of the control to System 74.0. Modify the Alignment property of the control to Center. Now that we have added our label controls to our view controller, our next step is to start adding the rest of our controls that will make up our user interface. So let's proceed to the next section. Adding the Enable Monitoring UISwitch control Our next step is to add a switch control to our view controller; this will be responsible for determining whether or not we are to monitor our battery levels and send out alert e-mails whenever our battery life is running low on our iOS device. This can be achieved by following these simple steps: From Object Library, select-and-drag a (UILabel) Label control, and add this to the bottom right-hand corner of our view controller. Modify the Text property of the control to Enable Monitoring:. Modify the Font property of the control to System 17.0. Modify the Alignment property of the control to Left. Next, from Object Library, select-and-drag a (UISwitch) Switch control to the right of the Enable Monitoring label. Next, from the Attributes Inspector section, change the value of State to On. Then, change the value of On Tint to Default. Now that we have added our Enable Monitoring switch control to our BatteryMonitor View controller, our next step is to add the Send E-mail Alert switch that will be responsible for sending out e-mail alerts if it has determined that the battery levels have fallen below our threshold. So, let's proceed with the next section. Adding the Send E-mail Alert UISwitch control Now, we need to add another switch control to our view that will be responsible for sending e-mail alerts. This can be achieved by following these simple steps: From Object Library, select-and-drag another (UILabel) Label control, and add this underneath our Enable Monitoring label. Modify the Text property of the control to Send E-mail Alert:. Modify the Font property of the control to System 17.0. Modify the Alignment property of the control to Left. Next, from Object Library, select-and-drag a (UISwitch) Switch control to the right of the Send Email Alert label. Next, from the Attributes Inspector section, change the value of State to On. Then, change the value of On Tint to Default. To duplicate a UILabel and/or UISwitch control and have them retain the same attributes, you can use the keyboard shortcut Command + D. You can then update the Text label for the newly added control. Now that we have added our Send E-mail Alert button to our BatteryMonitor view controller, our next step is to add the Fill Gauge Levels switch that will be responsible for filling our battery gauge when it has been set to ON. Adding the Fill Gauge Levels UISwitch control Now, we need to add another switch control to our view that will be responsible for determining whether our gauge should be filled to show the amount of battery remaining. This can be achieved by following these simple steps: From Object Library, select-and-drag another (UILabel) Label control, and add this underneath our Send E-mail Alert label. Modify the Text property of the control to Fill Gauge Levels:. Modify the Font property of the control to System 17.0. Modify the Alignment property of the control to Left. Next, from Object Library, select-and-drag a (UISwitch) Switch control to the right of the Fill Gauge Levels label. Next, from the Attributes Inspector section, change the value of State to On. Then, change the value of On Tint to Default. Now that we have added our Fill Gauge Levels switch control to our BatteryMonitor view controller, our next step is to add the Increment Bars stepper that will be responsible for increasing the number of bar cells within our battery gauge.
Read more
  • 0
  • 0
  • 9687
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €18.99/month. Cancel anytime
article-image-playing-swift
Packt
23 Dec 2014
23 min read
Save for later

Playing with Swift

Packt
23 Dec 2014
23 min read
Xcode ships with both a command line interpreter and a graphical interface called playground that can be used to prototype and test Swift code snippets. Code typed into the playground is compiled and executed interactively, which permits a fluid style of development. In addition, the user interface can present a graphical view of variables as well as a timeline, which can show how loops are executed. Finally, playgrounds can mix and match code and documentation, leading to the possibility of providing example code as playgrounds and using playgrounds to learn how to use existing APIs and frameworks. This article by Alex Blewitt, the author of Swift Essentials, will present the following topics: How to create a playground Displaying values in the timeline Presenting objects with Quick Look Running asynchronous code Using playground live documentation Generating playgrounds with Markdown and AsciiDoc Limitations of playgrounds (For more resources related to this topic, see here.) Getting started with playgrounds When Xcode is started, a welcome screen is shown with various options, including the ability to create a playground. Playgrounds can also be created from the File | New | Playground menu. Creating a playground Using either the Xcode welcome screen (which can be opened by navigating to Window | Welcome to Xcode) or navigating to File | New | Playground, create MyPlayground in a suitable location targeting iOS. Creating the playground on the Desktop will allow easy access to test Swift code, but it can be located anywhere on the filesystem. Playgrounds can be targeted either towards OS X applications or towards iOS applications. This can be configured when the playground is created, or by switching to the Utilities view by navigating to View | Utilities | Show File Inspector or pressing Command + Option + 1 and changing the dropdown from OS X to iOS or vice versa.   When initially created, the playground will have a code snippet that looks as follows: // Playground - noun: a place where people can play import UIKit var str = "Hello, playground" Playgrounds targeting OS X will read import Cocoa instead. On the right-hand side, a column will show the value of the code when each line is executed. In the previous example, the word Hello, playgr... is seen, which is the result of the string assignment. By grabbing the vertical divider between the Swift code and the output, the output can be resized to show the full text message:   Alternatively, by moving the mouse over the right-hand side of the playground, the Quick Look icon (the eye symbol) will appear; if clicked on, a pop-up box will show the full details:   Viewing the console output The console output can be viewed on the right-hand side by opening the Assistant Editor. This can be opened by pressing Command + Option + Enter or by navigating to View | Assistant Editor | Show Assistant Editor. This will show the result of any println statements executed in the code. Add a simple for loop to the playground and show the Assistant Editor: for i in 1...12 { println("I is (i)") } The output is shown on the right-hand side:   The assistant editor can be configured to be displayed in different locations, such as at the bottom, or stacked horizontally or vertically by navigating to the View | Assistant Editor menu. Viewing the timeline The timeline shows what other values are displayed as a result of executing the code. In the case of the print loop shown previously, the output was displayed as Console Output in the timeline. However, it is possible to use the playground to inspect the value of an expression on a line, without having to display it directly. In addition, results can be graphed to show how the values change over time. Add another line above the println statement to calculate the result of executing an expression, (i-6)*(i-7), and store it in a variable, j: for i in 1...12 { var j = (i-7) * (i-6) println("I is (i)") } On the line next to the variable definition, click on the add variable history symbol (+), which is in the right-hand column (visible when the mouse moves over that area). After it is clicked on, it will change to a (o) symbol and display the graph on the right-hand side. The same can be done for the println statement as well:   The slider at the bottom, indicated by the red tick mark, can be used to slide the vertical bar to see the exact value at certain points:   To show several values at once, use additional variables to hold the values and display them in the timeline as well: for i in 1...12 { var j = (i-7) * (i-6) var k = i println("I is (i)") }   When the slider is dragged, both values will be shown at the same time. Displaying objects with QuickLook The playground timeline can display objects as well as numbers and simple strings. It is possible to load and view images in a playground using classes such as UIImage (or NSImage on OS X). These are known as QuickLook supported objects, and by default include: Strings (attributed and unattributed) Views Class and struct types (members are shown) Colors It is possible to build support for custom types in Swift, by implementing a debugQuickLookObject method that returns a graphical view of the data. Showing colored labels To show a colored label, a color needs to be obtained first. When building against iOS, this will be UIColor; but when building against OS X, it will be NSColor. The methods and types are largely equivalent between the two, but this article will focus on the iOS types. A color can be acquired with an initializer or by using one of the predefined colors that are exposed in Swift using methods: import UIKit // AppKit for OS X let blue = UIColor.blueColor() // NSColor.blueColor() for OS X The color can be used in a UILabel, which displays a text string in a particular size and color. The UILabel needs a size, which is represented by a CGRect, and can be defined with an x and y position along with a width and height. The x and y positions are not relevant for playgrounds and so can be left as zero: let size = CGRect(x:0,y:0,width:200,height:100) let label = UILabel(frame:size)// NSLabel for OS X Finally, the text needs to be displayed in blue and with a larger font size: label.text = str // from the first line of the code label.textColor = blue label.font = UIFont.systemFontOfSize(24) // NSFont for OS X When the playground is run, the color and font are shown in the timeline and available for quick view. Even though the same UILabel instance is being shown, the timeline and the QuickLook values show a snapshot of the state of the object at each point, making it easy to see what has happened between changes.   Showing images Images can be created and loaded into a playground using the UIImage constructor (or NSImage on OS X). Both take a named argument, which is used to find an image with the given name from the playground's Resources folder. To download a logo, open Terminal.app and run the following commands: $ mkdir MyPlayground.playground/Resources $ curl http://alblue.bandlem.com/images/AlexHeadshotLeft.png > MyPlayground.playground/Resources/logo.png An image can now be loaded in Swift with: let logo = UIImage(named:"logo") The location of the Resources associated with a playground can be seen in the File Inspector utilities view, which can be opened by pressing Command + Option + 1. The loaded image can be displayed using QuickLook or by adding it to the "value history:   It is possible to use a URL to acquire an image by creating an NSURL with NSURL(string:"http://..."), then loading the contents of the URL with NSData(contentsOfURL:), and finally using UIImage(data:) to convert it to an image. However, as Swift will keep re-executing the code over and over again, the URL will be hit multiple times in a single debugging session without caching. It is recommended that NSData(contentsOfURL:) and similar networking classes be avoided in playgrounds. Advanced techniques The playground has its own framework, XCPlayground, which can be used to perform certain tasks. For example, individual values can be captured during loops for later analysis. It also permits asynchronous code to continue to execute once the playground has finished running. Capturing values explicitly It is possible to explicitly add values to the timeline by importing the XCPlayground framework and calling XCPCaptureValue with a value that should be displayed in the timeline. This takes an identifier, which is used both as the title and for group-related data values in the same series. When the value history button is selected, it essentially inserts a call to XCPCaptureValue with the value of the expression as "the identifier. For example, to add the logo to the timeline automatically: import XCPlayground XCPCaptureValue("logo",logo)   It is possible to use an identifier to group the data that is being shown in a loop with the identifier representing categories of the values. For example, to display a list of all even and odd numbers between 1 and 6, the following code could be used: for n in 1...6 { if n % 2 == 0 {    XCPCaptureValue("even",n)    XCPCaptureValue("odd",0) } else {    XCPCaptureValue("odd",n)    XCPCaptureValue("even",0) } } The result, when executed, will look as follows:   Running asynchronous code By default, when the execution hits the bottom of the playground, the execution stops. In most cases, this is desirable, but when asynchronous code is involved, execution might need to run even if the main code has finished executing. This might be the case if networking data is involved or if there are multiple tasks whose results need to be synchronized. For example, wrapping the previous even/odd split in an asynchronous call will result in no data being displayed: dispatch_async(dispatch_get_main_queue()) { for n in 1...6 {    // as before } } This uses one of Swift's language features: the dispatch_async method is actually a two-argument method that takes a queue and a block type. However, if the last argument is a block type, then it can be represented as a trailing closure rather than an argument. To allow the playground to continue executing after reaching the bottom, add the following call: XCPSetExecutionShouldContinueIndefinitely() Although this suggests that the execution will run forever, it is limited to 30 seconds of runtime, or whatever is the value displayed at the bottom-right corner of the screen. This timeout can be changed by typing in a new value or using the + and – buttons to increase/decrease time by one second.   Playgrounds and documentation Playgrounds can contain a mix of code and documentation. This allows a set of code samples and explanations to be mixed in with the playground itself. Although there is no way of using Xcode to add sections in the UI at present, the playground itself is an XML file that can be edited using an external text editor such as TextEdit.app. Learning with playgrounds As playgrounds can contain a mixture of code and documentation, it makes them an ideal format for viewing annotated code snippets. In fact, Apple's Swift Tour book can be opened as a playground file. Xcode documentation can be searched by navigating to the Help | Documentation and API Reference menu, or by pressing Command + Shift + 0. In the search field that is presented, type Swift Tour and then select the first result. The Swift Tour book should be presented in Xcode's help system:   A link to download and open the documentation as a playground is given in the first section; if this is downloaded, it can be opened in Xcode as a standalone playground. This provides the same information, but allows the code examples to be dynamic and show the results in the window:   A key advantage of learning through playground-based documentation is that the code can be experimented with. In the Simple Values section of the documentation, where myVariable is assigned, the right-hand side of the playground shows the values. If the literal numbers are changed, the new values will be recalculated and shown on the right-hand side. Some examples are presented solely in playground form; for example, the "Balloons demo, which was used in the introduction of Swift in the WWDC 2014 keynote, is downloadable as a playground from https://developer.apple.com/swift/resources/. Note that the Balloons playground requires OS X 10.10 and Xcode 6.1 to run. Understanding the playground format A playground is an OS X bundle, which means that it is a directory that looks like a single file. If a playground is selected either in TextEdit.app or in Finder, then it looks like a regular file:   Under the covers, it is actually a directory: $ ls -FMyPlayground.playground/ Inside the directory, there are a number of files: $ ls -1 MyPlayground.playground/* MyPlayground.playground/Resources MyPlayground.playground/contents.xcplayground MyPlayground.playground/section-1.swift MyPlayground.playground/timeline.xctimeline The files are as follows: The Resources directory, which was created earlier to hold the logo image The contents.xcplayground file, which is an XML table of contents of the files that make up the playground The section-1.swift file, which is the Swift file created by default when a new playground is created, and contains the code that is typed in for any new playground content The timeline.xctimeline file, which is an automatically generated file containing timestamps of execution, which the runtime generates when executing a Swift file and the timeline is open The table of contents file defines which runtime environment is being targeted (for example, iOS or OS X), a list of sections, and a reference to the timeline file: <playground version='3.0' sdk='iphonesimulator'> <sections>    <code source-file-name='section-1.swift'/> </sections> <timeline fileName='timeline.xctimeline'/> </playground> This file can be edited to add new sections, provided that it is not open in Xcode at the same time. An Xcode playground directory is deleted and recreated whenever changes are made in Xcode. Any Terminal.app windows open in that directory will no longer show any files. As a result, using external tools and editing the files in place might result in changes being lost. In addition, if you are using ancient versions of control systems, such as SVN and CVS, you might find your version control metadata being wiped out between saves. Xcode ships with the industry standard Git version control system, which should be preferred instead. Adding a new documentation section To add a new documentation section, ensure that the playground is not open in Xcode and then edit the contents.xcplayground file. The file itself can be opened by right-clicking on the playground in Finder and choosing Show Package Contents:   This will open up a new Finder window, with the contents displayed as a top-level set of elements. The individual files can then be opened for editing by right-clicking on the contents.xcplayground file, choosing Open With | Other..., and selecting an application, such as TextEdit.app.   Alternatively, the file can be edited from the command line using an editor such as pico, vi, or emacs. Although there are few technology debates more contentious than whether vi or emacs is better, the recommended advice is to learn how to be productive in at least one of them. Like learning to touch-type, being productive in a command-line editor is something that will pay dividends in the future if the initial learning challenge can be overcome. For those who don't have time, pico (also known as nano) can be a useful tool in command-line situations, and the on-screen help makes it easier to learn to use. Note that the carat symbol (^) means control, so ^X means Control + X. To add a new documentation section, create a directory called Documentation, and inside it, create a file called hello.html. The HTML file is an HTML5 document, with a declaration and a body. A minimal file looks like: <!DOCTYPE html> <html> <body>    <h1>Welcome to Swift Playground</h1> </body> </html> The content needs to be added to the table of contents (contents.xcplayground) in order to display it in the playground itself, by adding a documentation element under the sections element: <playground version='3.0' sdk='iphonesimulator'> <sections>    <code source-file-name='section-1.swift'/>    <documentation relative-path='hello.html'/> </sections> <timeline fileName='timeline.xctimeline'/> </playground> The relative-path attribute is relative to the Documentation directory. All content in the Documentation directory is copied between saves in the timeline and can be used to store other text content such as CSS files. Binary content, including images, should be stored in the Resources directory. When viewed as a playground, the content will be shown in the same window as "the documentation:   If the content is truncated in the window, then a horizontal rule can be added at the bottom with <hr/>, or the documentation can be styled, as shown in the next section. Styling the documentation As the documentation is written in HTML, it is possible to style it using CSS. For example, the background of the documentation is transparent, which results in the text overlapping both the margins as well as the output. To add a style sheet to the documentation, create a file called stylesheet.css in the Documentation directory and add the following content: body { background-color: white } To add the style sheet to the HTML file, add a style sheet link reference to the head element in hello.html: <head> <link rel="stylesheet" type="text/css" href="stylesheet.css"/> </head> Now when the playground is opened, the text will have a solid white background and will not be obscured by the margins:   Adding resources to a playground Images and other resources can also be added to a playground. Resources need to be added to a directory called Resources, which is copied as is between different versions of the playground. To add an image to the document, create a Resources folder and then insert an image. For example, earlier in this article, an image was downloaded by using the following commands: $ mkdir MyPlayground.playground/Resources $ curl http://alblue.bandlem.com/images/AlexHeadshotLeft.png > MyPlayground.playground/Resources/logo.png The image can then be referred to in the documentation using an img tag and a relative path from the Documentation directory: <img src="../Resources/logo.png" alt="Logo"/> Other supported resources (such as JPEG and GIF) can be added to the Resources folder as well. It is also possible to add other content (such as a ZIP file of examples) to the Resources folder and provide hyperlinks from the documentation to the resource files. <a href="../Resources/AlexBlewitt.vcf">Download contact card</a> Additional entries in the header The previous example showed the minimum amount of content required for playground documentation. However, there are other meta elements that can be added to the document that have specific purposes and which might be found in other playground examples on the internet. Here is a more comprehensive example of using meta elements: <!DOCTYPE html> <html lang="en"> <head>    <meta charset="utf-8"/>    <link rel="stylesheet" type="text/css" href="stylesheet.css"/>    <title>Welcome to Swift Playground</title>    <meta name="xcode-display" content="render"/>    <meta name="apple-mobile-web-app-capable" content="yes"/>    <meta name="viewport" content="width=device-width,maximum-scale=1.0"/> </head> <body>...</body> </html> In this example, the document is declared as being written in English (lang="en" on the html element) and in the UTF-8 character set. The <meta charset="utf-8"/> should always be the first element in the HTML head section, and the UTF-8 encoding should always be preferred for writing documents. If this is missed, it will default to a different encoding, such as ISO-8859-1, which can lead to strange characters appearing. Always use UTF-8 for writing HTML documents. The link and title are standard HTML elements that associate the style sheet "(from before) and the title of the document. The title is not displayed in Xcode, but it can be shown if the HTML document is opened in a browser instead. As the documentation is reusable between playgrounds and the web, it makes sense to "give it a sensible title. The link should be the second element after the charset definition. In fact, all externally linked resources—such as style sheets and scripts—should occur near the top of the document. This allows the HTML parser to initiate the download of external resources as soon as possible. This also includes the HTML5 prefetch link type, which is not supported in Safari or playground at the time of writing. The meta tags are instructions to Safari to render it in different ways (Safari is the web engine that is used to present the documentation content in playground). Safari-specific meta tags are described at https://developer.apple.com/library/safari/documentation/AppleApplications/Reference/SafariHTMLRef/Articles/MetaTags.html and include the following: The xcode-display=render meta tag, which indicates that Xcode should show the content of the document instead of the HTML source code when opening in Xcode The apple-mobile-web-app-capable=yes meta tag, which indicates that Safari should show this fullscreen if necessary when running on a "mobile device The viewport=width=device-width,maximum-scale=1.0 meta tag, which "allows the document body to be resized to fit the user's viewable area without scaling Generating playgrounds automatically The format of the playground files are well known, and several utilities have been created to generate playgrounds from documentation formats, such as Markdown or AsciiDoc. These are text-based documentation formats that provide a standard means to generate output documents, particularly HTML-based ones. Markdown Markdown (a word play on markup) was created to provide a standard syntax to generate web page documentation with links and references in a plain text format. More information about Markdown can be found at the home page (http://daringfireball.net/projects/markdown/), and more about the standardization of Markdown into CommonMark (used by StackOverflow, GitHub, Reddit, and others) can be found at http://commonmark.org. Embedding code in documentation is fairly common in Markdown. The file is treated as a top-level document, with sections to separate out the documentation and the code blocks. In CommonMark, these are separated with back ticks (```), often with the name of the language to add different script rendering types: ## Markdown Example ##This is an example CommonMark document. Blank lines separate paragraphs. Code blocks are introduced with three back-ticks and closed with back-ticks:```swift println("Welcome to Swift") ```Other text and other blocks can follow below. The most popular tool for converting Markdown/CommonMark documents into playgrounds (at the time of writing) is Jason Sandmeyer's swift-playground-builder at https://github.com/jas/swift-playground-builder/. The tool uses Node to execute JavaScript and can be installed using the npm install -g swift-playground-builder command. Both Node and npm can be installed from "http://nodejs.org. Once installed, documents can be translated using playground --platform ios --destination outdir --stylesheet stylesheet.css. If code samples should not be editable, then the --no-refresh argument should be added. AsciiDoc AsciiDoc is similar in intent to Markdown, except that it can render to more backends than just HTML5. AsciiDoc is growing in popularity for documenting code, primarily because the standard is much more well defined than Markdown is. The de facto standard translation tool for AsciiDoc is written in Ruby and can be installed using the sudo gem install asciidoctor command. Code blocks in AsciiDoc are represented by a [source] block. For Swift, this will be [source, swift]. The block starts and ends with two hyphens (--): .AsciiDoc ExampleThis is an example AsciiDoc document. Blank lines separate paragraphs. Code blocks are introduced with a source block and two hyphens:[source, swift] -- println("Welcome to Swift") -- Other text and other code blocks can follow below --. AsciiDoc files typically use the ad extension, and the ad2play tool can be installed from James Carlson's repository at https://github.com/jxxcarlson/ad2play. Saving the preceding example as example.ad and running ad2play example.ad will result in the generation of the example.playground file. More information about AsciiDoc, including the syntax and backend, can be found at the AsciiDoc home page at http://www.methods.co.nz/asciidoc/ or on the Asciidoctor home page at http://asciidoctor.org. Limitations of playgrounds Although playgrounds can be very powerful for interacting with code, there are some limitations that are worth being aware of. There is no debugging support in the playground. It is not possible to add a breakpoint and use the debugger and find out what the values are. Given that the UI allows tracking values—and that it's very easy to add new lines with just the value to be tracked—this is not much of a hardship. Other limitations of playgrounds include: Only the simulator can be used for the execution of iOS-based playgrounds. This prevents the use of hardware-specific features that might only be present on a device. The performance of playground scripts is mainly driven based on how many lines are executed and how much output is saved by the debugger. It should not be used to test the performance of performance-sensitive code. Although the playground is well suited to present user interface components, it cannot be used for user input. Anything requiring entitlements (such as in-app purchases or access to iCloud) is not possible in playground at the time of writing. Note that while earlier releases of playground did not support custom frameworks, Xcode 6.1 permits frameworks to be loaded into playground, provided that the framework is built and marked as public and that it is in the same workspace as the playground Summary This article presented playgrounds, an innovative way of running Swift code with graphical representations of values and introspection of running code. Both expressions and the timeline were presented as a way of showing the state of the program at any time, as well as graphically inspecting objects using QuickLook. The XCPlayground framework can also be used to record specific values and allow asynchronous code to be executed. Being able to mix code and documentation into the same playground is also a great way of showing what functions exist, and how to create self-documenting playgrounds was presented. In addition, tools for the creation of such playgrounds using either AsciiDoc or Markdown (CommonMark) were introduced. Resources for Article: Further resources on this subject: Using OpenStack Swift [article] Sparrow iOS Game Framework - The Basics of Our Game [article] Adding Real-time Functionality Using Socket.io [article]
Read more
  • 0
  • 0
  • 9669

article-image-tour-xcode
Packt
06 Feb 2015
13 min read
Save for later

Tour of Xcode

Packt
06 Feb 2015
13 min read
In this article, written by Jayant Varma, the author of Xcode 6 Essentials, we shall look at Xcode closely as this is going to be the tool you would use quite a lot for all aspects of your app development for Apple devices. It is a good idea to know and be familiar with the interface, the sections, shortcut keys, and so on. (For more resources related to this topic, see here.) Starting Xcode Xcode, like many other Mac applications, is found in the Applications folder or the Launchpad. On starting Xcode, you will be greeted with the launch screen that offers some entry points for working with Xcode. Mostly, you will select Create a new Xcode project or Check out an existing project , if you have an existing project to continue work on. Xcode remembers what it was doing last, so if you had a project or file open, it will open up those windows again. Creating a new project After selecting the Create a new project option, we are guided via a wizard that helps us get started. Selecting the project type The first step is to select what type of project you want to create. At the moment, there are two distinct types of projects, mobile (iOS) or desktop (OS X) that you can create. Within each of those types, you can select the type of project you want. The screenshot displays a standard configuration for iOS application projects. The templates used when the selected type of project is created are self sufficient, that is, when the Run button is pressed, the app compiles and runs. It might do nothing, as this is a minimalistic template. On selecting the type of project, we can select the next step: Setting the project options This step allows selecting the options, namely setting the application name, the organization name, identifier, language, and devices to support. In the past, the language was always set to Objective-C, however with Xcode 6, there are two options: objective-C and Swift Setting the project properties On creation, the main screen is displayed. Here it offers the option to change other details related to the application such as the version number and build. It also allows you to configure the team ID and certificates used for signing the application to test on a mobile device or for distribution to the App Store. It also allows you to set the compatibility for earlier versions. The orientation and app icons, splash screens, and so on are also set from this screen. If you want to set these up later on in the project, it is fine, this can be accessed at any time and does not stop you from development. It needs to be set prior to deploying it on a device or creating an App Store ready application. Xcode overview Let us have a look at the Xcode interface to familiarize ourselves with the same as it would help improve productivity when building your application. The top section immediately following the traffic light (window chrome) displays a Play and Stop button. This allows the project to run and stop. The breadcrumb toolbar displays the project-specific settings with respect to the product and the target. With an iOS project, it could be a particular simulator for iPhone, iPad, and so on, or a physical device (number 5 in the following screenshot). Just under this are vertical areas that are the main content area with all the files, editors, UI, and so on. These can be displayed or hidden as required and can be stacked vertically or horizontally. The distinct areas in Xcode are as follows: Project navigation (number1) Editor and assistant editor (number 2 ) and (number 3 ) Utility/inspector (number 4 ) The toolbar (number 5 ) and (number 6 ) These sections can be switched on and off (shown or hidden) as required to make space for other sections or more screen space to work with: Sections in Xcode The project section The project navigation section has three sub sections, the topmost being the project toolbar that has eight icons. These can be seen as in the following screenshot. The next sub section contains the project files and all the assets required for this project. The bottom most section consists of recently edited files and filters: You can use the keyboard shortcuts to access these areas quickly with the CMD + 1...8 keys. The eight areas available under project navigation are key and for the beginner to Xcode, this could be a bit daunting. When you run the project, the current section might change and display another where you might wonder how to get back to the project (file) navigator. Getting familiar with these is always helpful and the easiest way to navigate between these is the CMD + 1..8 keys. Project navigator ( CMD + 1 ): This displays all of the files, folders, assets, frameworks, and so on that are part of this project. This is displayed as a hierarchical view and is the way that a majority of developers access their files, folders, and so on. Symbol navigator ( CMD + 2 ): This displays all of the classes, members, and methods that are available in them. This is the easiest way to navigate quickly to a method/function, attribute/property. Search navigator ( CMD + 3 ): This allows you to search the project for a particular match. This is quite useful to find and replace text. Issues navigator ( CMD + 4 ): This displays the warning and errors that occur while typing your code or on building and running it. This also displays the results of the static analyzer. Tests navigator ( CMD + 5 ); This displays the tests that you have present in your code either added by yourself or the default ones created with the project. Debug navigator ( CMD + 6 ): This displays the information about the application when you choose to run it. It has some amazing detailed information on CPU usage, memory usage, disk usage, threads, and so on. Breakpoint navigator ( CMD + 7 ): This displays all the breakpoints in your project from all files. This also allows you to create exception and symbolic breakpoints. Log navigator ( CMD + 8 ): This displays a log of all actions carried out, namely compiling, building, and running. This is more useful when used to determine the results of automated builds The editor and assistant editor sections The second area contains the editor and assistant editor sections. These display the code, the XIB (as appropriate), storyboard files, device previews, and so on. Each of the sub sections have a jump bar on the top that relates to files and allow for navigating back and forth in the files and display the location of the file in the workspace. To the right from this is a mini issues navigator that displays all warnings and errors. In the case of the assistant editors, it also displays two buttons: one to add a new assistant editor area and another to close it.   Source code editors While we are looking at the interface, it is worth noting that the Xcode code editor is a very advanced editor with a lot of features, which is now seen as standard with a lot of text editors. Some of the features that make working with Xcode easier are as follows: Code folding : This feature helps to hide code at points such as the function declaration, loops, matching brace brackets, and so on. When a function or portion of code is folded, it hides it from view, thereby allowing you to view other areas of the code that would not be visible unless you scrolled. Syntax highlighting : This is one of the most useful features as it helps you, the developer, to visually, at a glance, differentiate your source code from variables, constants, and strings. Xcode has syntax highlighting for a couple of languages as mentioned earlier. Context help : This is one of the best features whereby when you hover over a word in the source code with OPT pressed, it shows a dotted underline and the cursor changes to a question mark. When you click on a word with the dotted underline and the question mark cursor, it displays a popup with details about that word. It also highlights all instances of that word in the file. The popup details as much information as available. If it is a variable or a function that you have added to the code, then it will display the name of the file where it was declared. If it is a word that is contained in the Apple libraries, then it displays the description and other additional details. Context jump : This is another cool feature that allows jumping to the point of declaration of that word. This is achieved by clicking on a word while keeping the CMD button pressed. In many cases, this is mainly helpful to know how the function is declared and what parameters it expects. It can also be useful to get information on other enumerators and constants used with that function. The jump could be in the same file as where you are editing the code or it could be to the header files where they are declared. Edit all in scope : This is a cool feature where you can edit all of the instances of the word together rather than using search and replace. A case scenario is if you want to change the name of a variable and ensure that all instances you are using in the file are changed but not the ones that are text, then you can use this option to quickly change it. Catching mistakes with fix-it : This is another cool feature in Xcode that will save you a lot of time and hassle. As you type text, Xcode keeps analyzing the code and looking for errors. If you have declared a variable and not used it in your code, Xcode immediately draws attention to it suggesting that the variable is an unused variable. However, if it was supposed to be a pointer and you have declared it without *; Xcode immediately flags it as an error that the interface type cannot be statically allocated. It offers a fix-it solution of inserting * and the code has a greyed * character showing where it will be added. This helps the developer fix commonly overlooked issues such as missing semicolons, missing declarations, or misspelled variable names. Code completion : This is the bit that makes writing code so much easier, type in a few letters of the function name and Xcode pops up a list of functions, constants, methods, and so on that start with those letters and displays all of the required parameters (as applicable) including the return type. When selected, it adds the token placeholders that can be replaced with the actual parameter values. The results might vary from person to person depending on the settings and the speed of the system you run Xcode on. The assistant editor The assistant editor is mainly used to display the counterparts and related files to the file open in the primary editor (generally used when working with Objective-C where the .h or.m files are the related files). The assistant editors track the contents of the editor. Xcode is quite intelligent and knows the corresponding sections and counterparts. When you click on a file, it opens up in the editor. However, pressing the OPT + Shift while clicking on the file, you would be provided with an interactive dialog to select where to open the file. The options include the primary editor or the assistant editor. You can also add assistant editors as required.   Another way to open a file quickly is to use the Open Quickly option, which has a shortcut key of CMD + Shift + O . This displays a textbox that allows accessing a file from the project. The utility/inspector section The last section contains the inspector and library. This section changes based on the type of file selected in the current editor. The inspector has 6 tabs/sections and they are as follows: The file inspector ( CMD + OPT + 1 ): This displays the physical file information for the file selected. For code files, it is the text encoding, the targets that it belongs to, and the physical file path. While for the storyboard, it is the physical file path and allows setting attributes such as auto layout and size classes (new in Xcode 6). The quick help inspector ( CMD + OPT + 2 ): This displays information about the class or object selected. The identity inspector ( CMD + OPT + 3 ): This displays the class name, ID, and others that identify the object selected. The attributes inspector ( CMD + OPT + 4 ): This displays the attributes for the object selected as if it is the initial root view controller, does it extend under the top bars or not, if it has a navigation bar or not, and others. This also displays the user-defined attributes (a new feature with Xcode 6). The size inspector ( CMD + OPT + 5 ): This displays the size of the control selected and the associated constraints that help position it on the container. The connections inspector ( CMD + OPT + 6 ): This displays the connections created in the Interface Builder between the UI and the code. The lower half of this inspector contains four options that help you work efficiently, they are as follows: The file template library : This contains the options to create a new class, protocol. The options that are available when selecting the File | New option from the menu. The code snippets library : This is a wonderful but not widely used option. This can hold code snippets that can help you avoid writing repetitive blocks of code in your app. You can drag and drop the snippet to your code in the editor. This also offers features such as shortcuts, scopes, platforms, and languages. So you can have a shortcut such as appDidLoad (for example) that inserts the code to create and populate a button. This is achieved simply by setting the platform as appropriate to iOS or OS X. After creating a code snippet, as soon as you type the first few characters, the code snippet shows up in the list of autocomplete options; The object library : This is the toolbox that contains all of the controls that you need for creating your UI, be it a button, a label, a Table View, view, View Controller, or anything else. Adding a code snippet is as easy as dragging the selected code from the editor onto the snippet area. It is a little tricky because the moment you start dragging, it could break your selection highlight. You need to select the text, click (hold) and then drag it. The media library : This contains the list of all images and other media types that are available to this project/workspace. Summary In this article, you have seen a quick tour of Xcode, keeping the shortcuts and tips handy as they really do help get things done faster. The code snippets are a wonderful feature that allow for quickly setting up commonly used code with shortcut keywords. Resources for Article: Further resources on this subject: Introducing Xcode Tools for iPhone Development [article] Xcode 4 ios: Displaying Notification Messages [article] Linking OpenCV to an iOS project [article]
Read more
  • 0
  • 0
  • 9665

article-image-introduction-watchkit
Packt
04 Sep 2015
7 min read
Save for later

Introduction to WatchKit

Packt
04 Sep 2015
7 min read
In this article by Hossam Ghareeb, author of the book Application Development with Swift, we will talk about a new technology, WatchKit, and a new era of wearable technologies. Now technology is a part of all aspects of our lives, even wearable objects. You can see smart watches such as the new Apple watch or glasses such as Google glass. We will go through the new WatchKit framework to learn how to extend your iPhone app functionalities to your wrist. (For more resources related to this topic, see here.) Apple watch Apple watch is a new device on your wrist that can be used to extend your iPhone app functionality; you can access the most important information and respond in easy ways using the watch. The watch is now available in most countries in different styles and models so that everyone can find a watch that suits them. When you get your Apple watch, you can pair it with your iPhone. The watch can't be paired with the iPad; it can only be paired with your iPhone. To run third-party apps on your watch, iPhone should be paired with the watch. Once paired, when you install any app on your iPhone that has an extension for the watch, the app will be installed on the watch automatically and wirelessly. WatchKit WatchKit is a new framework to build apps for Apple watch. To run third-party apps on Apple watch, you need the watch to be connected to the iPhone. WatchKit helps you create apps for Apple watch by creating two targets in Xcode: The WatchKit app: The WatchKit app is an executable app to be installed on your watch, and you can install or uninstall it from your iPhone. The WatchKit app contains the storyboard file and resources files. It doesn't contain any source code, just the interface and resource files. The WatchKit extension: This extension runs on the iPhone and has the InterfaceControllers file for your storyboard. This extension just contains the model and controller classes. The actions and outlets from the previous WatchKit app will be linked to these controller files in the WatchKit extension. These bundles—the WatchKit extension and WatchKit app—are put together and packed inside the iPhone application. When the user installs the iPhone app, the system will prompt the user to install the WatchKit app if there is a paired watch. Using WatchKit, you can extend your iOS app in three different ways: The WatchKit app As we mentioned earlier, the WatchKit app is an app installed on Apple watch and the user can find it in the list of Watch apps. The user can launch, control, and interact with the app. Once the app is launched, the WatchKit extension on the iPhone app will run in the background to update a user interface, perform any logic required, and respond to user actions. Note that the iPhone app can't launch or wake up the WatchKit extension or the WatchKit app. However, the WatchKit extension can ask the system to launch the iPhone app and this will be performed in the background. Glances Glances are single interfaces that the user can navigate between. The glance view is just read-only information, which means that you can't add any interactive UI controls such as buttons and switches. Apps should use glances to display very important and timely information. The glance view is a nonscrolling view, so your glance view should fit the watch screen. Avoid using tables and maps in interface controllers and focus on delivering the most important information in a nice way. Once the user clicks on the glance view, the watch app will be launched. The glance view is optional in your app. The glance interface and its interface controller files are a part of your WatchKit extension and WatchKit app. The glance interface resides in a storyboard, which resides in the WatchKit app. The interface controller that is responsible for filling the view with the timely important information is located in the WatchKit extension, which runs in the background in the iPhone app, as we said before. Actionable notifications For sure, you can handle and respond to local and remote notifications in an easy and fast way using Apple watch. WatchKit helps you build user interfaces for the notification that you want to handle in your WatchKit app. WatchKit helps you add actionable buttons so that the user can take action based on the notification. For example, if a notification for an invitation is sent to you, you can take action to accept or reject the notification from your wrist. You can respond to these actions easily in interface controllers in WatchKit extension. Working with WatchKit Enough talking about theory, lets see some action. Go to our lovely Xcode and create a new single-view application and name it WatchKitDemo. Don't forget to select Swift as the app language. Then navigate to File | New | Target to create a new target for the WatchKit app: After you select the target, in the pop-up window, from the left side under iOS choose Apple Watch and select WatchKit App. Check the following screenshot: After you click on Next, it will ask you which application to embed the target in and which scenes to include. Please check the Include Notification Scene and Include Glance Scene options, as shown in the following screenshot: Click on Finish, and now you have an iPhone app with the built-in WatchKit extension and WatchKit app. Xcode targets Now your project should be divided into three parts. Check the following screenshot and let's explain these parts: As you see in this screenshot, the project files are divided into three sections. In section 1, you can see the iPhone app source files, interface files or storyboard, and resources files. In section 2, you can find the WatchKit extension, which contains only interface controllers and model files. Again, as we said before, this extension also runs in iPhone in the background. In section 3, you can see the WatchKit app, which runs in Apple watch itself. As we see, it contains the storyboard and resources files. No source code can be added in this target. Interface controllers In the WatchKit extension of your Xcode project, open InterfaceController.swift. You will find the interface controller file for the scene that exists in Interface.storyboard in the WatchKit app. The InterfaceController file extends from WKInterfaceController, which is the base class for interface controllers. Forget the UI classes that you were using in the iOS apps from the UIKit framework, as it has different interface controller classes in WatchKit and they are very limited in configuration and customization. In the InterfaceController file, you can find three important methods that explain the lifecycle of your controller: awakeWithContext, willActivate, and didDeactivate. Another important method that can be overridden for the lifecycle is called init, but it's not implemented in the controller file. Let's now explain the four lifecycle methods: init: You can consider this as your first chance to update your interface elements. awakeWithContext: This is called after the init method and contains context data that can be used to update your interface elements or to perform some logical operations on these data. Context data is passed between interface controllers when you push or present another controller and you want to pass some data. willActivate: Here, your scene is about to be visible onscreen, and its your last chance to update your UI. Try to put simple UI changes here in this method so as not to cause freezing in UI. didDeactivate: Your scene is about to be invisible and, if you want to clean up your code, it's time to stop animations or timers. Summary In this article, we covered a very important topic: how to develop apps for the new wearable technology, Apple watch. We first gave a quick introduction about the new device and how it can communicate with paired iPhones. We then talked about WatchKit, the new framework, that enables you to develop apps for Apple watch and design its interface. Apple has designed the watch to contain only the storyboard and resources files. All logic and operations are performed in the iPhone app in the background. Resources for Article: Further resources on this subject: Flappy Swift [article] Playing with Swift [article] Using OpenStack Swift [article]
Read more
  • 0
  • 0
  • 9475

article-image-memory-management
Packt
17 Mar 2016
18 min read
Save for later

Memory Management

Packt
17 Mar 2016
18 min read
In this article by Andrew Wagner, author of the book Learning Swift - Second Edition, we will see how to manage memory. As we know that when using an app, not much is worse than it being slow and unresponsive. Computer users have come to expect every piece of software to respond immediately to every interaction. Even the most feature-rich app will be ruined if it is unpleasant to use, because it won't manage the device's resources effectively. Also, with the growing popularity of mobile computers and devices, it is more important than ever to write software that efficiently uses battery power. One of the aspects of writing software that has the largest impact on both responsiveness and battery power is memory management. (For more resources related to this topic, see here.) In this article, we will discuss techniques specific to Swift that allow us to manage memoryin order to ensure that our code remains responsive and minimizes its effect on battery life. We will do so by covering: Value types versus reference types Automatic reference counting Value types versus reference types All variables and constants in Swift are stored in memory. In fact, unless you explicitly write data to the filesystem, everything you create is going to be in memory. In Swift, there are two different types of categories. These two categories are value types and reference types. The only way they differ is how they behave when they are assigned to new variables, passed into methods, or captured in closures. Essentially, they only differ when you try to assign a new variable or constant to the value of an existing variable or constant. A value type is always copied when being assigned somewhere new, while a reference type is not. Before we look at what exactly this means in more detail, let's go over how we determine whether a type is a value type or a reference type. Determining between a value type or reference type A value type is any type that is defined either as a structure or an enumeration, while all classes are reference types. This is easy to determine for your own custom types based on how you declared them. Beyond this, all of the built-in types for Swift, such as strings, arrays, and dictionaries, are value types. If you are ever uncertain, you can test any type you want in a playground to see whether its behavior is consistent with a value type or a reference type. The simplest behavior to check is what happens on assignment. Behaviour on assignment When a value type is reassigned, it is copied so that afterwards, each variable or constant holds a distinct value that can be changed independently. Let's look at a simple example using a string: var value1 = "Hello" var value2 = value1 value1 += " World!" print(value1) // "Hello World!" print(value2) // "Hello" As you can see, when value2 is set to value1, a copy is created. That makes it so that when we append "World!" to value1, value2 remains unchanged as "Hello". We can visualize them as two completely separate entities: On the other hand, let's look at what happens with a reference type: class Person { var name: String init(name: String) { self.name = name } } var reference1 = Person(name: "Kai") var reference2 = reference1 reference1.name = "Naya" print(reference1.name) // "Naya" print(reference2.name) // "Naya" As you can see, when we changed the name of reference1, reference2 was also changed. So why is this? As the name implies, reference types are simply references to an instance. When you assign a reference to another variable or constant, both are actually referring to the exact same instance. We can visualize this as two separate objects referencing the same instance: In the real world, this would be like two kids sharing a toy. Both can play with the toy but if one breaks the toy, it is broken for both kids. However, it is important to realize that if you assign a reference type to a new value, it does not change the value it was originally referencing: reference2 = Person(name: "Kai") print(reference1.name) // "Naya" print(reference2.name) // "Kai" As you can see, we assigned reference2 to an entirely different Person instance, so they can now be manipulated independently. We could then visualize this as two separate references to two separate instances: This would be like buying a new toy for one of the kids. This actually shows you that a reference type is really a special version of a value type. The difference is that a reference type is not itself an instance of any type. It is simply a reference to an instance. You can copy the reference so that you then have two variables referencing the same instance, or you can give a variable a completely new reference to a new instance. With reference types, there is an extra layer of indirection based on the sharing of instances between multiple variables. Now that we know this, the simplest way to verify whether a type is a value type or a reference type is to check its behavior when it is being assigned. If the second value is changed when you modify the first value, it means that whatever type you are testing is a reference type. Behavior on input Another place where the behavior of a value type differs from that of a reference type is when passing them into functions and methods. However, the behavior is very simple to remember if you look at passing a variable or constant into a function as just another assignment. This means that when you pass a value type into a function, it is copied, while a reference type still shares the same value: func setNameOfPerson(person: Person, var to name: String) { person.name = name name = "Other Name" } Here, we have defined a function that takes both a reference type,Person, and a value type,String. When we update the person's data within the function, the person we passed in is also changed: var person = Person(name: "Sarah") var newName = "Jamison" setNameOfPerson(person, to: newName) print(person.name) // "Jamison" print(newName) // "Jamison" However, when we change the string within the function, the string passed in remains unchanged. The place where things get a little more complicated is with in-out parameters. An in-out parameter is actually a reference to the passed-in instance. This means that it will treat a value type as if it were a reference type: func updateString(inout string: String) { string = "Other String" } var someString = "Some String" updateString(&someString) print(someString) // "Other String" As you can see, when we changed the in-out version of string within the function, it also changed the someString variable outside of the function just as if it were a reference type. If we remember that a reference type is just a special version of a value type where the value is a reference, we can infer what will be possible with an in-out version of a reference type. When we define an in-out reference type, we actually have a reference to a reference; that reference is then the one that is pointing to a reference. We can visualize the difference between an in-out value type and an in-out reference type like this: If we simply change the value of this variable, we will get the same behavior as if it were not an in-out parameter. However, by making it an in-out parameter, we can also change where the inner reference is referring to: func updatePerson(inout insidePerson: Person) { insidePerson.name = "New Name" insidePerson = Person(name: "New Person") } var person2 = person updatePerson(&person) print(person.name) // "New Person" print(person2.name) // "New Name" We start out by creating a second reference—person2—to the same instance as the person variable that currently has the name Jamison from before. After that, we pass the original person variable into our updatePerson method and have this: In this method, we first change the name of the existing person to a new name. We can see in the output that the name of person2 is also changed because both insidePerson inside the function and person2 are still referencing the same instance: However, we then also assign insidePerson to a completely new instance of the Person reference type. This results in person and person2 outside of the function pointing at two completely different instances of Person, leaving the name of person2 to be New Name and updating the name of person to New Person: Here, by defining insidePerson as an in-out parameter, we were able to change where the passed-in variable was referencing to. This can help us visualize all of the different options as one type pointing to another. At any point, any of these arrows can be pointed to something new using an assignment, and the instance can always be accessed through the references. Closure capture behaviour The last behavior we have to worry about is when variables are captured within closures. Closures can actually use variables that were defined in the same scope as the closure itself: var nameToPrint = "Kai" var printName = { print(nameToPrint) } printName() // "Kai" This is very different from the normal parameters that we have seen before. We don't actually specify nameToPrint as a parameter, nor do we pass it in when calling the method. Instead, the closure is capturing the nameToPrint variable that is defined before it. These types of captures act similarly to in-out parameters in functions. When a value type is captured, it can be changed, and this will change the original value as well: var outsideName = "Kai" var setName = { outsideName = "New Name" } print(outsideName) // "Kai" setName() print(outsideName) // "New Name" As you can see, outsideName was changed after the closure was called. This is exactly like an in-out parameter. When a reference type is captured, any changes will also be applied to the outside version of the variable: var outsidePerson = Person(name: "Kai") var setPersonName = { outsidePerson.name = "New Name" } print(outsidePerson.name) // "Kai" setPersonName() print(outsidePerson.name) // "New Name" This is also exactly like an in-out parameter. The only place where capture behavior differs from an in-out parameter is that you cannot reassign the captured reference value to a new instance. If you try, the compiler will produce an error. This means that it is safe to treat captured variables as in-out parameters because the compiler will stop you in the only place where they differ. The other part of closure capture that we need to keep in mind is that changing the captured value after the closure is defined will still affect the value within the closure. We could take advantage of this in order to use the printName closure we defined previously to print any name: nameToPrint = "Kai" printName() // Kai nameToPrint = "New Name" printName() // "New Name" As you can see, we can change what printName prints out by changing the value of nameToPrint. This behavior is actually very hard to track down when it happens accidently, so it is usually a good idea to avoid capturing variables in closures whenever possible. In this case, we were taking advantage of the behavior, but more often than not, it will cause bugs. Here, it would be better to just pass what we want to print as an argument. Another way to avoid this behavior is to use a feature called capture lists. With this, you can specify variables that you want to capture by copying them: nameToPrint = "Original Name" var printNameWithCapture = { [nameToPrint] in print(nameToPrint) } printNameWithCapture() // "Original Name" nameToPrint = "New Name" printNameWithCapture() // "Original Name" A capture list is defined at the beginning of a closure before any parameters. It is a comma-separated list of all the variables being captured that we want to copy within square brackets. In this case, we requested that nameToPrint be copied so that when we change it later, it does not affect the value that is printed out. Automatic reference counting Now that we understand the different ways in which data is represented in Swift, we can look into how we can manage memory better. Every instance we create takes up memory. Naturally, it wouldn't make sense to keep all data around forever. Swift needs to be able to free up memory to be used for other purposes once our program doesn't need it anymore. This is the key to managing memory in our apps. We need to make sure that Swift can free up all of the memory that we no longer need as soon as possible. The way that Swift knows it can free up memory is when the code can no longer access an instance. If there is no longer any variable or constant referencing an instance, it can be repurposed for another instance. This is called "freeing the memory" or "deleting the object". Since value types are always copied when they are reassigned or passed into functions, they can be immediately deleted once they go out of scope. We can look at a simple example to get the full picture: func printSomething() { let something = "Hello World!" print(something) } Here we have a very simple function that prints out "Hello World!". When printSomething is called, something is assigned to a new instance of String with the value "Hello World!". After print is called, the function exits, and something is therefore no longer in scope. At that point, the memory being taken up by something can be freed. While this is very simple, reference types are much more complex. At a high level, an instance of a reference type is deleted at the point when there are no longer any references to the instance in scope anymore. This is relatively straightforward to understand but it gets more complex in the details. The Swift feature that manages this is called automatic reference counting, or ARC for short. Object relationships The key to ARC is that every object has relationships with one or more variables. This can be extended to include the idea that all objects have a relationship with other objects. For example, a car object would contain objects for its four tires, engine, and so on. It would also have a relationship with its manufacturer, dealership, and owner. ARC uses these relationships to determine when an object can be deleted. In Swift, there are three different types of relationships: strong, weak, and unowned. Strong The first, and default, type of relationship is a strong relationship. It says that a variable requires that the instance it is referring to must always exist as long as the variable is still in scope. This is the only behavior available for value types. When an instance no longer has any strong relationships to it, it will be deleted. A great example of this type of relationship is with a car, which must have a steering wheel: class SteeringWheel {} class Car { var steeringWheel: SteeringWheel init(steeringWheel: SteeringWheel) { self.steeringWheel = steeringWheel } } By default, the steeringWheel property has a strong relationship with the SteeringWheel instance it is initialized with. Conceptually, this means that the car itself has a strong relationship with the steering wheel. As long as the car exists, it must have a relationship with a steering wheel. Since steeringWheel is declared as a variable, we could change the steering wheel of the car, which would remove the old strong relationship and add a new one; however, a strong relationship will always exist. If we were to create a new instance of Car and store it in a variable, that variable would have a strong relationship to the car: let wheel = SteeringWheel() let car = Car(steeringWheel: wheel) Let's break down all of the relationships in this code. First, we create the wheel constant and assign it to a new instance of SteeringWheel. This sets up a strong relationship from wheel to the new instance. We do the same thing with the car constant, but this time, we also pass in the wheel constant to the initializer. Now, not only does car have a strong relationship with the new Car instance, but the Car initializer also creates a strong relationship from the steeringWheel property and with the same instance as the wheel constant: So what does this relationship graph mean for memory management? At this time, the Car instance has one strong relationship: the car constant, and the SteeringWheel instance has two strong relationships: the wheel constant and the steeringWheel property of the Car instance. This means that the Car instance will be deleted as soon as the car constant goes out of scope. On the other hand, the SteeringWheel instance will only be deleted after both the wheel constant goes out of scope and the Car instance is deleted. You can envision a strong reference counter on every instance in your program. Every time a strong relationship is set up to an instance, the counter goes up. Every time an object strongly referencing it gets deleted, the counter goes down. If that counter ever goes back to zero, the instance is deleted. The other important thing to realize is that all relationships are only in one direction. Just because the Car instance has a strong relationship with the SteeringWheel instance does not mean the SteeringWheel instance has any relationship back. You could add your own relationship back by adding a car property to the SteeringWheel class, but you have to be careful when doing this, as we will see in the strong reference cycle section coming up. Weak The next type of relationship in Swift is a weak relationship. It allows one object to reference another without enforcing that it always exists. A weak relationship does not contribute to the reference counter of an instance, which means that the addition of a weak relationship does not increase the counter, nor does it decrease the counter when removed. Since a weak relationship cannot guarantee that it will always exist, it must always be defined as an optional. A weak relationship is defined using the weak keyword before the variable declaration: class SteeringWheel { weak var car: Car? } This allows a SteeringWheel to have a car assigned to it, without enforcing that the car never be deleted. The car initializer can then assign this backwards reference to itself: class Car { var steeringWheel: SteeringWheel init(steeringWheel: SteeringWheel) { self.steeringWheel = steeringWheel self.steeringWheel.car = self } } If the car is ever deleted, the car property of SteeringWheel will automatically be set to null. This allows us to gracefully handle the scenario in which a weak relationship refers to an instance that has been deleted. Unowned The final type of relationship is an unowned relationship. This relationship is almost identical to a weak relationship. It also allows one object to reference another without contributing to the strong reference count. The only difference is that an unowned relationship does not need to be declared as optional, and it uses the unowned keyword instead of weak. It acts very similarly to an implicitly unwrapped optional. You can interact with an unowned relationship as if it were a strong relationship, but if the unowned instance has been deleted and you try to access it, your entire program will crash. This means that you should only use unowned relationships in scenarios where the unowned object will never actually be deleted while the primary object still exists. You may ask then, "Why would we not always use a strong relationship instead?" The answer is that sometimes unowned or weak references are needed to break something called a strong reference cycle. Summary Memory management is often considered difficult to understand, but when you break it down, you can see that it is relatively straightforward. In this chapter, we saw that in Swift, there are value types and reference types, which are critical to understanding how we can reduce memory usage and eliminate memory leaks. Memory leaks are created when an object has a strong reference to itself through a third party, which is called a strong reference cycle. We must also be careful that we keep at least one strongreference to every object that we want to stay around, or we may lose them prematurely. With practice, you will get better at both preventing and fixing memory problems. You will write streamlined apps that keep your users' computers running smoothly. Resources for Article: Further resources on this subject: Concurrency and Parallelism with Swift 2[article] Your First Swift 2 Project[article] Exploring Swift[article]
Read more
  • 0
  • 0
  • 9455
article-image-cocos2d-iphone-surfing-through-scenes
Packt
29 Dec 2010
10 min read
Save for later

Cocos2d for iPhone: Surfing Through Scenes

Packt
29 Dec 2010
10 min read
  Cocos2d for iPhone 0.99 Beginner's Guide Make mind-blowing 2D games for iPhone with this fast, flexible, and easy-to-use framework! A cool guide to learning cocos2d with iPhone to get you into the iPhone game industry quickly Learn all the aspects of cocos2d while building three different games Add a lot of trendy features such as particles and tilemaps to your games to captivate your players Full of illustrations, diagrams, and tips for building iPhone games, with clear step-by-step instructions and practical examples         Read more about this book       (For more resources on Cocos2d, see here.) We'll be doing a lot of things in this article, so let's get started. Aerial Gun, a vertical shooter game Let's talk about the game we will be making. Aerial Gun, as I said earlier, is a vertical shooter game. That means you will be in control of an airship which will move vertically. Actually, the airship won't be moving anywhere (well except to the left and right); what is really going to move here is the background, giving the sense the airship is the one moving. The player will be able to control the airship by using accelerometer controls. We'll also provide some areas where the player can touch to fire bullets or bombs to destroy the enemies. Enemies will be appearing at different time intervals and will have some different behaviors attached to them. For example, some of them could just move towards the airship, others may stay there and shoot back, and so on. We'll do it in a way you can create more custom behaviors later. For this game we will be using the Cocos2d template again, just because it is the easier way to have a project properly set up, at least to begin our work. So, follow the same steps as when we created the Coloured Stones game. Just open Xcode and go to the File menu, select to create a new project. Then choose the Cocos2d template (the simple one, without any physics engine) and give a name to the project. I will call it AerialGun. Once you do that, your new project should be opened. Creating new scenes We will begin this new game by first doing a couple of scenes other than the one that holds the actual game. If you take a look at the class that the template generates, at first sight you won't find what would appear to be a scene. That is because the template handles that in a confusing fashion, at least for people who are just getting started with Cocos2d. Let's take a look at that. Open the newly generated HelloWorldScene.m file. This is the same code in which we based our first game. This time we will analyze it so you understand what it is doing behind scenes. Take a look at the first method of the implementation of the HelloWorld Layer: +(id) scene{ // 'scene' is an autorelease object. CCScene *scene = [CCScene node]; // 'layer' is an autorelease object. HelloWorld *layer = [HelloWorld node]; // add layer as a child to scene [scene addChild: layer]; // return the scene return scene;} If you remember well, this is the method that get's called in the AppDelegate when the Director needs to start running with a scene. So why are we passing the method of a layer instead of an instance of a CCScene class? If you pay attention to the +(id)scene method of the layer, what it does is to instantiate a CCScene object, then it instantiates a HelloWorld object (the layer), and then it adds that layer to the scene and returns it. This actually works as you have witnessed and is pretty quick to set up, and get you up and running. However, sometimes you will need to have you own custom scenes, that is a class that inherits from CCScene and extends it in some fashion. Now we are going to create some of the scenes that we need for this game and add a layer to each one. Then when it is time to work with the game scene we will modify it to match our needs. Before doing anything, please change the name of the HelloWorldlayer to GameLayer and the name of the HelloWorldScene to GameScene, just as we did back then with our first game. Time for action – creating the splash and main menu scene We will begin with a simple scene, the splash screen. A splash screen is the first thing that appears as you launch a game. Well, the second if you count the Default.png image. The objective of this screen is to show the player some information about the developer, other companies that helped, and so on. Most times you will just show a couple and logos and move to the main menu. So, what we will do now is put a new Default.png image, then create the SplashScene. The Default.png image is located in your project's Resources group folder and it is the first image that is shown when the application is launched. You should always have one, so that something is shown while the application is being launched. This happens before anything is initialized, so you can't do anything else other than show this image. Its dimensions must be 320 * 480 (when developing for older generation iPhones), so if your game is supposed to be in landscape mode, you should rotate the image with any graphics software before including it in your project. The SplashScene is going to show a sprite for a moment, then fade it, show another one and then move to the GameScene. Let's add a new file to the project. Select New File (CMD + N) from the File menu, then select Objective-C class (we are going to do it from scratch anyways) and name it SplashScene. This file will hold both the SplashScene and the SplashLayer classes. The SplashLayer will be added as a child of the SplashScene, and inside the layer we will add the sprites. Before writing any code, add to the project the three splash images I created for you. You can find them in the companion files folder. Once you have them added into your project we can begin working on the SplashScene. The following is the SplashScene.h: #import <Foundation/Foundation.h>#import "cocos2d.h"#import "MainMenuScene.h"@interface SplashScene : CCScene { }@end@interface SplashLayer : CCLayer { }@end And the SplashScene.m file: #import "SplashScene.h" //Here is the implementation of the SplashScene@implementation SplashScene- (id) init{ self = [super init]; if (self != nil) { [self addChild:[SplashLayer node]]; } return self;}-(void)dealloc{ [super dealloc];}@end//And here is the implementation of the SplashLayer@implementation SplashLayer- (id) init{ if ((self = [super init])) { isTouchEnabled = YES; NSMutableArray * splashImages = [[NSMutableArray alloc]init]; for(int i =1;i<=3;i++) { CCSprite * splashImage = [CCSprite spriteWithFile:[NSString stringWithFormat:@"splash%d.png",i]]; [splashImage setPosition:ccp(240,160)]; [self addChild:splashImage]; if(i!=1) [splashImage setOpacity:0]; [splashImages addObject:splashImage]; } [self fadeAndShow:splashImages]; } return self;}//Now we add the methods that handle the image switching-(void)fadeAndShow:(NSMutableArray *)images{ if([images count]<=1) { [images release]; [[CCDirector sharedDirector]replaceScene:[MainMenuScene node]]; } else { CCSprite * actual = (CCSprite *)[images objectAtIndex:0]; [images removeObjectAtIndex:0]; CCSprite * next = (CCSprite *)[images objectAtIndex:0]; [actual runAction:[CCSequence actions:[CCDelayTime actionWithDuration:2], [CCFadeOut actionWithDuration:1],[CCCallFuncN actionWithTarget:self selector:@selector(remove:)],nil]]; [next runAction:[CCSequence actions:[CCDelayTime actionWithDuration:2], [CCFadeIn actionWithDuration:1],[CCDelayTime actionWithDuration:2], [CCCallFuncND actionWithTarget:self selector:@selector(cFadeAndShow: data:) data:images],nil]]; } }-(void) cFadeAndShow:(id)sender data:(void*)data{ NSMutableArray * images = (NSMutableArray *)data; [self fadeAndShow:images];}-(void)remove:(CCSprite *)s{ [s.parent removeChild:s cleanup:YES];}-(void)dealloc{ [super dealloc];}@end As you may notice, I have put together two classes in only one file. You can do this with any number of classes, as long you don't get lost in such a long file. Generally, you will create a pair of files (the .m and .h) for each class, but as the SplashScene class has very little code, I'd rather put it there. For this to work properly, we need to make some other changes. First, open the AerialGunAppDelegate.m file and change the line where the the Director starts running the GameScene. We want it to start by running the SplashScene now. So replace that line with the following: [[CCDirector sharedDirector] runWithScene:[SplashScene node]]; Also remember to import your SplashScene.h file in order for the project to properly compile. Finally, we have to create the MainMenuScene, which is the scene the Director will run after the last image has faded out. So, let's create that one and leave it blank for now. The following is the MainMenuScene.h file: #import <Foundation/Foundation.h>#import "cocos2d.h"@interface MainMenuScene : CCScene { }@end@interface MainMenuLayer : CCLayer { }@end The following is the MainMenuScene.m file: #import "MainMenuScene.h"@implementation MainMenuScene- (id) init{ self = [super init]; if (self != nil) { [self addChild:[MainMenuLayer node]]; } return self;}-(void)dealloc{ [super dealloc];}@end@implementation MainMenuLayer- (id) init{ if ((self = [super init])) { isTouchEnabled = YES; } return self;}-(void)dealloc{ [super dealloc];}@end That would be all for now. Run the project and you should see the first image appear. Then fade to the next one after a while and continue till the last one. Once the last one has faded out, we move on to the MainMenuScene. What just happened? Creating a new scene is as easy as that. You can see from the MainMenuScene code that what we are doing is quite simple; when the MainMenuScene gets created we just instantiate the MainMenuLayer and add it to the scene. That layer is where we will later add all the necessary logic for the main menu. The MainMenuScene as well as the SplashScene both inherit from the CCScene class. This class is just another CCNode. Let's take a little look at the logic behind the SplashScene: NSMutableArray * splashImages = [[NSMutableArray alloc]init];for(int i =1;i<=3;i++){ CCSprite * splashImage = [CCSprite spriteWithFile:[NSString stringWithFormat:@"splash%d.png",i]]; [splashImage setPosition:ccp(240,160)]; [self addChild:splashImage]; if(i!=1) [splashImage setOpacity:0]; [splashImages addObject:splashImage];} [self fadeAndShow:splashImages]; This piece of code is from the SplashLayer init method. What we are doing here is creating an array that will hold any amount of sprites (in this case, three of them). Then we create and add those sprites to it. Finally, the fadeAndShow method is called, passing that newly created array to it. The fadeAndShow method is responsible for fading the images it has. It grabs the first image in the array (after that, the sprite is removed from the array). It then grabs the next one. Then it applies actions to both of them to fade them in and out. The last action of the second sprite's action is a CCCallFuncND, which we use to call the fadeAndShow method again with the modified array. This occurs if there is more than one remaining sprite in the array. If there isn't, the fadeAndShow method calls the Director's replaceScene method with the MainMenuScene. I have made the SplashLayer logic, so you can add more splash images to the array (or leave just one) if you like. Generally, just one or two images will be more than enough.
Read more
  • 0
  • 0
  • 9208

article-image-iphone-javascript-web-20-integration
Packt
04 Oct 2011
7 min read
Save for later

iPhone JavaScript: Web 2.0 Integration

Packt
04 Oct 2011
7 min read
  (For more resources on iPhone JavaScript, see here.) Introduction The mashup applications allow us to exchange data with other web applications or services. Web 2.0 applications provide this feature through different mechanisms. Currently, some of the most popular websites like YouTube, Flickr, and Twitter provide a way for exchanging data through their API's. From the point of view of the user interfaces, mashups allow us to build rich interfaces for our application. The first recipe for this article will cover embedding a standard RSS feed information. Later in our application we'll delve into YouTube, Facebook, Twitter, and Flickr and build some interesting mashup web applications for the iPhone. Embedding an RSS feed Our goal for this recipe will be to read an RSS feed and present the information provided n our application. In practice, we're going to use a feed offered by The New York Times newspaper, where each item provides a summary and a link to the original web page where the information resides. You could also choose another RSS feed for testing this recipe. The code for this recipe can be found at code/ch10/rss.html in the code bundle provided on the Packtpub site. Getting ready Make sure iWebKit is installed in your computer before continuing. How to do it... As you've learned in the previous recipes, you need to create an XHTML file with the required headers for loading the files provided by iWebKit: <link href="../iwebkit/css/style.css" rel="stylesheet" media="screen" type="text/css" /><scriptsrc="../iwebkit/javascript/functions.js" type="text/javascript"></script> The second step will be to build our simple user interface containing only a top bar and an unordered list with one item. The top bar is added with the following lines: <div id="topbar"> <div id="title">RSS feed</div></div> To add the unordered list , use the following code: <div id="content"> <ul class="pageitem"> <li class="textbox"> <p> <script src="http://rssxpress.ukoln.ac.uk/lite/ viewer/?rss=http://www.nytimes.com/services/xml/ rss/nyt/HomePage.xml" type="text/javascript"></script> </p> </li> </ul></div> Finally, you should add the code for closing the body and html tags and save the new file as rss.html. After loading your new application, you will see a screen, as shown in the screenshot: If you click on one of the items, Safari Mobile will open the web page for the article, as shown in the following screenshot: How it works... For avoiding complexity and keeping our recipe as simple as possible, we used a free web service provided by RSSxpress. This service is called RSSxpressLite and it works by returning a chunk of JavaScript code. This code inserts an HTML table, containing a summary and a link for each item provided by the referenced RSS feed. Thanks to this web service, we don't need to parse the response of the original feed; RSSxpressLite does the job for us. If the mentioned web service returns the code that we need, you should only write a small line of JavaScript code referring to the web service through its URL and pass as a parameter the RSS feed for displaying information. There's more... For learning more about RSSxpressLite, take a look at http://rssxpress.ukoln.ac.uk/lite/include/. Opening a YouTube video It is safe to say that everyone who uses the Internet knows of YouTube. It is one of the most popular websites in the world. Millions of people use YouTube to watch videos through an assortment of devices, such as PC's, tablets, and smartphones. Apple's devices are not an exception and of course we can watch YouTube videos on the iPhone and iPad. In this case, we're going to load a YouTube video when the user clicks on a specific button. The ink will open a new web page, which allows us to play it. The simple XHTML recipe can be found at code/ch10/youtube.html in the code bundle provided on the Packtpub site. Getting ready This recipe only requires the UiUIKit framework f or building the user interface for this application. You can use your favorite YouTube video for this recipe. By default, we're using a video provided by Apple introducing the new iPad 2 device. How to do it... Following the example from the previous recipe, create a new XHTML file called youtube.html and insert the standard headers for loading the UiUIKit framework. Then add the following CSS inside the <head> section to style the main button: <style type="text/css"> #btn { margin-right: 12px; }</style> Our graphical user interface will be completed by adding the following XHTML code: <div id="header"> <h1>YouTube video</h1></div><h1>Video</h1><p id="btn"> <a href="http://m.youtube.com/watch?v=Z_d6_gbb90I" class="button white">Watch</a></p> After loading the new application on your device, you will see a screen similar to the following screenshot: When the user clicks on our main button, Safari Mobile will go to the web page of the video at YouTube, as shown in the following screenshot: After clicking on the play button, the video will start playing. We can rotate our device for a better aspect ratio, as shown in the following screenshot: How it works... This recipe is pretty simple; we only need to create a link to the desired YouTube video. The most important thing to keep in mind is that we'll use a mobile-specific domain for loading our video to mobile devices. The URL is simply http://m.youtube.com, instead of the regular URL http://www.youtube.com. Posting on your Facebook wall The application developed for this recipe shows how to authenticate with Facebook and how to write a post on your public wall. If everything is successful, an alert box is used to report it to the user. Although there are myriad complex applications with better functionalities that can be built for Facebook, we will focus on simple posting in this recipe. This application will only allow you to post on your wall. For this you need to hardcode your Facebook account for posting. This is to keep the recipe as simple as possible and to get a good understanding of all the complex processes involved in dealing with the OAuth protocol used by Facebook. However, thanks to this open protocol, it is easier to allow secure authentication of APIs from web applications. Also, this recipe requires using a real Internet domain and a server with public access. Thus, you cannot test this application on your local machine. Our application needs to use a server- side language for which we'll use PHP. Currently, it's very easy to find hosting services for PHP applications. You can also find very cheap services for hosting your PHP code. You can find the complete code for this recipe at code/ch10/facebook/ in the code bundle provided on the Packtpub site. Getting ready To bu ild the application for this recipe, you need to have a public server with an Internet domain linked to it. Also, you must install a web server with a PHP interpreter and have the UiUIKit framework ready to use. You need to install the cURL library, which allows PHP to connect and communicate to many different types of servers. Two interesting resources for this issue are: http://www.php.net/manual/en/book.curl.php http://www.php.net/manual/en/curl.setup.php  
Read more
  • 0
  • 0
  • 9133

article-image-designing-simple-robust-object-detector-and-classifier
Packt
13 Jun 2016
19 min read
Save for later

Designing a Simple, Robust Object Detector and Classifier

Packt
13 Jun 2016
19 min read
In this article by Joseph Howse, author of the book, iOS Application Development with OpenCV 3, illustrates a scale-invariant,rotation-invariant approach to object detection and classification, using OpenCV 3and just 250 lines of custom C++ code. The technique relies on blob detection, histogram analysis, and SURF (or ORB if SURF is unavailable).The classifier is sensitive to colors as well as keypoints, and itcan work with a small number of training images. For background information, sample images, and a complete tutorial on how to integrate this detector and classifier into an iOS application, refer toChapter 5, Classifying Coins and Commodities in the book,iOS Application Development with OpenCV 3 (Packt Publishing, 2016). You could also use this article's C++ code on other platforms besides iOS. (For more resources related to this topic, see here.) Defining blobs and a blob detector For our purposes, a blob simply has an image and a label. The image is cv::Mat and the label is an unsigned integer. The label's default value is 0, which shall signify that the blob has not yet been classified. Create a new header file, Blob.h, and fill it with the following declaration of a Blob class: #ifndef BLOB_H #define BLOB_H   #include <opencv2/core.hpp>   class Blob { public:   Blob(const cv::Mat &mat, uint32_t label = 0ul);     /**    * Construct an empty blob.    */   Blob();     /**    * Construct a blob by copying another blob.    */   Blob(const Blob &other);     bool isEmpty() const;     uint32_t getLabel() const;   void setLabel(uint32_t value);     const cv::Mat &getMat() const;   int getWidth() const;   int getHeight() const;   private:   uint32_t label;     cv::Mat mat; };   #endif // BLOB_H A Blob's image does not change after construction, but the label may change as a result of our classification process. Note that most of Blob's methods have the const modifier, but of course,setLabel does not because it changes the label. Now, let's declare a BlobDetector class in another new header file, BlobDetector.h. This class provides a detect public method to analyze a given image and populate vector<Blob> based on detected objects in the image. Another public method, getMask, returns a thresholded version of the most recent image that the detect method received. Internally, BlobDetector uses several more matrices and vectors to hold intermediate results, including the mask, detected edges, detected contours, and hierarchy that describes the contours' relationship to each other. Here is the detector's declaration: class BlobDetector { public:   void detect(cv::Mat &image, std::vector<Blob>&blob,     double resizeFactor = 1.0, bool draw = false);     const cv::Mat &getMask() const;   private:   void createMask(const cv::Mat &image);     cv::Mat resizedImage;   cv::Mat mask;   cv::Mat edges;   std::vector<std::vector<cv::Point>> contours;   std::vector<cv::Vec4i> hierarchy; };   #endif // !BLOB_DETECTOR_H Later, in the Detecting blobs against a plain background section, we will define the methods' bodies in new files called Blob.cpp and BlobDetector.cpp. Defining blob descriptors and a blob classifier If you are familiar with keypoint matching, you know that a keypoint has a descriptor or set of descriptive statistics. Similarly, we can define a custom descriptor for a blob. As our classifier relies on histogram comparison and keypoint matching, let's say that a blob's descriptor consists of a normalized histogram and matrix of keypoint descriptors. The descriptor object is also a convenient place to put the label. Create a new header file, BlobDescriptor.h, and put the following declaration of a BlobDescriptor class in it: #ifndef BLOB_DESCRIPTOR_H #define BLOB_DESCRIPTOR_H   #include <opencv2/core.hpp>   class BlobDescriptor { public:   BlobDescriptor(const cv::Mat &normalizedHistogram,     const cv::Mat &keypointDescriptors, uint32_t label);     const cv::Mat &getNormalizedHistogram() const;   const cv::Mat &getKeypointDescriptors() const;   uint32_t getLabel() const;   private:   cv::Mat normalizedHistogram;   cv::Mat keypointDescriptors;   uint32_t label; };   #endif // !BLOB_DESCRIPTOR_H Note that BlobDescriptor is designed as an immutable class. All its methods, except the constructor, have the const modifier. Now, let's declare a BlobClassifier class in another new header file, BlobClassifier.h. Publicly, this class receives Blob objects via an update method (for reference blobs) and a classify method (for blobs that the detector found in the scene). Privately, BlobClassifier creates, owns, and compares BlobDescriptor objects that pertain to the Blob objects. Thus, BlobClassifier is the only part of our program that needs to deal with BlobDescriptor. BlobClassifier also owns instances of OpenCV classes that are responsible for keypoint detection, description, and matching. Here is our classifier's declaration: #ifndef BLOB_CLASSIFIER_H #define BLOB_CLASSIFIER_H   #import "Blob.h" #import "BlobDescriptor.h"   #include <opencv2/features2d.hpp>   class BlobClassifier { public:   BlobClassifier();     /**    * Add a reference blob to the classification model.    */   void update(const Blob &referenceBlob);     /**    * Clear the classification model.    */   void clear();     /**    * Classify a blob that was detected in a scene.    */   void classify(Blob &detectedBlob) const;   private:   BlobDescriptor createBlobDescriptor(const Blob &blob) const;   float findDistance(const BlobDescriptor &detectedBlobDescriptor,     const BlobDescriptor &referenceBlobDescriptor) const;     /**    * A feature detector and descriptor extractor.    * It finds features in images.    * Then, it creates descriptors of the features.    */   cv::Ptr<cv::Feature2D> featureDetectorAndDescriptorExtractor;     /**    * A descriptor matcher.    * It matches features based on their descriptors.    */   cv::Ptr<cv::DescriptorMatcher> descriptorMatcher;     /**    * Descriptors of the reference blobs.    */   std::vector<BlobDescriptor> referenceBlobDescriptors; };   #endif // !BLOB_CLASSIFIER_H Later, in the Classifying blobs by color and keypoints section, we will write the methods' bodies in new files called BlobDescriptor.cpp and BlobClassifier.cpp. Detecting blobs against a plain background Let's assume that the background has a distinctive color range, such as "cream to snow white". Our blob detector will calculate the image's dominant color range and search for large regions whose colors differ from this range. These anomalous regions will constitute the detected blobs. For small objects such as a bean or coin, a user can easily find a plain background such as a blank sheet of paper, plain table-top, plain piece of clothing, or even the palm of a hand. As our blob detector dynamically estimates the background color range, it can cope with various backgrounds and lighting conditions; it is not limited to a lab environment. Create a new file, BlobDetector.cpp, for the implementation of our BlobDetector class. (To review the header, refer back to the Defining blobs and a blob detector section.) At the top of BlobDetector.cpp, we will define several constants that pertain to the breadth of the background color range, the size and smoothing of the blobs, and the color of the blobs' rectangles in the preview image. Here is the relevant code: #include <opencv2/imgproc.hpp>   #include "BlobDetector.h"   const double MASK_STD_DEVS_FROM_MEAN = 1.0; const double MASK_EROSION_KERNEL_RELATIVE_SIZE_IN_IMAGE = 0.005; const int MASK_NUM_EROSION_ITERATIONS = 8;   const double BLOB_RELATIVE_MIN_SIZE_IN_IMAGE = 0.05;   const cv::Scalar DRAW_RECT_COLOR(0, 255, 0); // Green Of course, the heart of BlobDetector is its detect method. Optionally, the method creates a downsized version of the image for faster processing. Then, we call a helper method, createMask, to perform thresholding and erosion on the (resized) image. We pass the resulting mask to the cv::Canny function to perform Canny edge detection. We pass the edge mask to the cv::findContours function, which populates a vector of contours, in the vector<vector<cv::Point>> format. That is to say, each contour is a vector of points. For each contour, we find the points' bounding rectangle. If we are working with a resized image, we restore the bounding rectangle to the original scale. We reject rectangles that are very small. Finally, for each accepted rectangle, we put a new Blob object in the output vector and optionally draw the rectangle in the original image. Here is the detect method's implementation: void BlobDetector::detect(cv::Mat &image,   std::vector<Blob>&blobs, double resizeFactor, bool draw) {   blobs.clear();     if (resizeFactor == 1.0) {     createMask(image);   } else {     cv::resize(image, resizedImage, cv::Size(), resizeFactor,       resizeFactor, cv::INTER_AREA);     createMask(resizedImage);   }     // Find the edges in the mask.   cv::Canny(mask, edges, 191, 255);     // Find the contours of the edges.   cv::findContours(edges, contours, hierarchy, cv::RETR_TREE,     cv::CHAIN_APPROX_SIMPLE);     std::vector<cv::Rect> rects;   int blobMinSize = (int)(MIN(image.rows, image.cols) *     BLOB_RELATIVE_MIN_SIZE_IN_IMAGE);   for (std::vector<cv::Point> contour : contours) {       // Find the contour's bounding rectangle.     cv::Rect rect = cv::boundingRect(contour);       // Restore the bounding rectangle to the original scale.     rect.x /= resizeFactor;     rect.y /= resizeFactor;     rect.width /= resizeFactor;     rect.height /= resizeFactor;       if (rect.width < blobMinSize || rect.height < blobMinSize) {       continue;     }       // Create the blob from the sub-image inside the bounding     // rectangle.     blobs.push_back(Blob(cv::Mat(image, rect)));       // Remember the bounding rectangle in order to draw it later.     rects.push_back(rect);   }     if (draw) {     // Draw the bounding rectangles.     for (const cv::Rect &rect : rects) {       cv::rectangle(image, rect.tl(), rect.br(), DRAW_RECT_COLOR);     }   } } The getMask method simply returns the mask that we previously computed in the detect method: const cv::Mat &BlobDetector::getMask() const {   return mask; } The createMask helper method begins by finding the image's mean color and standard deviation using the cv::meanStdDev function. We calculate a range of background colors based on a certain number of standard deviations from the mean, as defined by the MASK_STD_DEVS_FROM_MEAN constant near the top of BlobDetector.cpp. We deem values outside this range to be foreground colors. Using the cv::inRange function, we map the background colors (in the image) to white (in the mask) and the foreground colors (in the image) to black (in the mask). Then, we create a square kernel using the cv::getStructuringElement function. Finally, we use the kernel in the cv::erode function to apply the erosion morphological operation to the mask. This has the effect of smoothing the black (foreground) regions such that they swallow up little gaps that are probably just noise. Here is the relevant code: void BlobDetector::createMask(const cv::Mat &image) {     // Find the image's mean color.   // Presumably, this is the background color.   // Also find the standard deviation.   cv::Scalar meanColor;   cv::Scalar stdDevColor;   cv::meanStdDev(image, meanColor, stdDevColor);     // Create a mask based on a range around the mean color.   cv::Scalar halfRange = MASK_STD_DEVS_FROM_MEAN * stdDevColor;   cv::Scalar lowerBound = meanColor - halfRange;   cv::Scalar upperBound = meanColor + halfRange;   cv::inRange(image, lowerBound, upperBound, mask);     // Erode the mask to merge neighboring blobs.   int kernelWidth = (int)(MIN(image.cols, image.rows) *     MASK_EROSION_KERNEL_RELATIVE_SIZE_IN_IMAGE);   if (kernelWidth > 0) {     cv::Size kernelSize(kernelWidth, kernelWidth);     cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT,       kernelSize);     cv::erode(mask, mask, kernel, cv::Point(-1, -1),       MASK_NUM_EROSION_ITERATIONS);   } } That is the end of the blob detector's code. As you can see, it uses a general-purpose and rather linear approach, without any special cases for different kinds of objects.Moreover, we are using a separate blob detector and blob classifier, and this separation of responsibilities enables us to keep each class's implementation relatively simple. For completeness, note that the Blob class's constructors have straightforward implementations that copy the arguments. For the blob's image, we make a deep copy because the original may change. (For example, the original may be a subimage in a frame of video, and after detection we may draw rectangles atop the frame of video.) Similarly, Blob's getter and setter methods are self-explanatory. Create a new file, Blop.cpp, and fill it with the following implementation: #import "Blob.h"   Blob::Blob(const cv::Mat &mat, uint32_t label) : label(label) {   mat.copyTo(this->mat); }   Blob::Blob() { }   Blob::Blob(const Blob &other) : label(other.label) {   other.mat.copyTo(mat); }   bool Blob::isEmpty() const {   return mat.empty(); } uint32_t Blob::getLabel() const {   return label; } void Blob::setLabel(uint32_t value) {   label = value; } const cv::Mat &Blob::getMat() const {   return mat; } int Blob::getWidth() const {   return mat.cols; } int Blob::getHeight() const {   return mat.rows; } Classifying blobs by color and keypoints Our classifier operates on the assumption that a blob contains distinctive colors, distinctive keypoints, or both. To conserve memory and precompute as much relevant information as possible, we do not store images of the reference blobs, but instead we store histograms and keypoint descriptors. Create a new file, BlobClassifier.cpp, for the implementation of our BlobClassifier class. (To review the header, refer back to the Defining blob descriptors and a blob classifier section.) At the top of BlobDetector.cpp, we will define several constants that pertain to the number of histogram bins, the histogram comparison method, and the relative importance of the histogram comparison versus the keypoint comparison. Here is the relevant code: #include <opencv2/imgproc.hpp>   #include "BlobClassifier.h"   #ifdef WITH_OPENCV_CONTRIB #include <opencv2/xfeatures2d.hpp> #endif   const int HISTOGRAM_NUM_BINS_PER_CHANNEL = 32; const int HISTOGRAM_COMPARISON_METHOD = cv::HISTCMP_CHISQR_ALT;   const float HISTOGRAM_DISTANCE_WEIGHT = 0.98f; const float KEYPOINT_MATCHING_DISTANCE_WEIGHT = 1.0f -   HISTOGRAM_DISTANCE_WEIGHT; Beware that the HISTOGRAM_NUM_BINS_PER_CHANNEL constant has a cubic relationship to memory usage. For each blob descriptor, we store a three-dimensional (BGR) histogram with HISTOGRAM_NUM_BINS_PER_CHANNEL^3 elements, and each element is a 32-bit floating point number. If the constant is 32, each histogram's size in megabytes is (32^3)*32/(10^6)=1.0. This is fine for a small set of reference descriptors. If the constant is 256 (the maximum number of bins for an 8-bit color channel), the histogram's size goes up to a whopping value of (256^3)*32/(10^6)=536.9 megabytes! For an iOS application, this is unacceptable, given the platform's memory constraints. At best, in a high-end iOS device, one gigabyte of RAM might be available to each application. Conservatively, you should worry if your app's memory usage approaches 100 megabytes. Remember that OpenCV's SURF implementation is in the xfeatures2d module, which is part of opencv_contrib. If opencv_contrib is available, let's define the WITH_OPENCV_CONTRIB preprocessor flag. Then, our code imports the <opencv/xfeatures2d.hpp> header, and we use SURF. Otherwise, we use ORB. This selection also affects the implementation of BlobClassifier's constructor. OpenCV provides factory methods for various feature detectors, descriptors, and matchers, so we simply have to use the right combination of factory methods for SURF with Flann matching or ORB with brute-force matching based on the Hamming distance. Here is the constructor's implementation: BlobClassifier::BlobClassifier() { #ifdef WITH_OPENCV_CONTRIB   featureDetectorAndDescriptorExtractor =     cv::xfeatures2d::SURF::create();   descriptorMatcher = cv::DescriptorMatcher::create("FlannBased"); #else   featureDetectorAndDescriptorExtractor = cv::ORB::create();   descriptorMatcher = cv::DescriptorMatcher::create( "BruteForce-HammingLUT"); #endif } The update method's implementation calls a helper method, createBlobDescriptor, and adds the resulting BlobDescriptor to a vector of reference descriptors: void BlobClassifier::update(const Blob &referenceBlob) {   referenceBlobDescriptors.push_back(     createBlobDescriptor(referenceBlob)); } The clear method's implementation discards all the reference descriptors such that the BlobClassifier reverts to its initial, untrained state: void BlobClassifier::clear() {   referenceBlobDescriptors.clear(); } The implementation of the classify method relies on another helper method, findDistance. For each reference descriptor, classify calls findDistance to obtain a measure of dissimilarity between the query blob's descriptor and reference descriptor. We find the reference descriptor with the least distance (best similarity) and return its label as the classification result. If there are no reference descriptors, classify returns 0, the "unknown" label. Here is classify's implementation: void BlobClassifier::classify(Blob &detectedBlob) const {   BlobDescriptor detectedBlobDescriptor =     createBlobDescriptor(detectedBlob);   float bestDistance = FLT_MAX;   uint32_t bestLabel = 0;   for (const BlobDescriptor &referenceBlobDescriptor :       referenceBlobDescriptors) {     float distance = findDistance(detectedBlobDescriptor,       referenceBlobDescriptor);     if (distance < bestDistance) {       bestDistance = distance;       bestLabel = referenceBlobDescriptor.getLabel();     }   }   detectedBlob.setLabel(bestLabel); } The createBlobDescriptor helper method is responsible for calculating a normalized histogram of Bloband keypoint descriptors and using them to build a new BlobDescriptor. To calculate the (non-normalized) histogram, we use the cv::calcHist function. Among its arguments, it requires three arrays to specify the channels we want to use, the number of bins per channel, and the range of each channel's values. To normalize the resulting histogram, we divide by the number of pixels in the blob's image. The following code, pertaining to the histogram, is the first half of implementation of createBlobDescriptor: BlobDescriptor BlobClassifier::createBlobDescriptor(   const Blob &blob) const {    const cv::Mat &mat = blob.getMat();   int numChannels = mat.channels();     // Calculate the histogram of the blob's image.   cv::Mat histogram;   int channels[] = { 0, 1, 2 };   int numBins[] = { HISTOGRAM_NUM_BINS_PER_CHANNEL,     HISTOGRAM_NUM_BINS_PER_CHANNEL,     HISTOGRAM_NUM_BINS_PER_CHANNEL };   float range[] = { 0.0f, 256.0f };   const float *ranges[] = { range, range, range };   cv::calcHist(&mat, 1, channels, cv::Mat(), histogram, 3,     numBins, ranges);     // Normalize the histogram.   histogram *= (1.0f / (mat.rows * mat.cols)); Now, we must convert the blob's image to grayscale and obtain keypoints and keypoint descriptors using the detect and compute methods of cv::Feature2D. With the normalized histogram and keypoint descriptors, we have everything that we need to construct and return a new BlobDescriptor. Here is the remainder of implementation of createBlobDescriptor: // Convert the blob's image to grayscale.   cv::Mat grayMat;   switch (numChannels) {     case 4:       cv::cvtColor(mat, grayMat, cv::COLOR_BGRA2GRAY);       break;     default:       cv::cvtColor(mat, grayMat, cv::COLOR_BGR2GRAY);       break;   }     // Detect features in the grayscale image.   std::vector<cv::KeyPoint> keypoints;   featureDetectorAndDescriptorExtractor->detect(grayMat,     keypoints);     // Extract descriptors of the features.   cv::Mat keypointDescriptors;   featureDetectorAndDescriptorExtractor->compute(grayMat,     keypoints, keypointDescriptors);     return BlobDescriptor(histogram, keypointDescriptors,     blob.getLabel()); } The findDistance helper method performs histogram comparison using the cv::compareHist function and keypoint matching using the match method of cv::DescriptorMatcher. Each of the resulting keypoint matches has a distance, and we sum these distances. Then, as an overall measure of distance between the two blob descriptors, we return a weighted average of the histogram distance and the total keypoint matching distance. Here is the relevant code: float BlobClassifier::findDistance(   const BlobDescriptor &detectedBlobDescriptor,   const BlobDescriptor &referenceBlobDescriptor) const {    // Calculate the histogram distance.   float histogramDistance = (float)cv::compareHist(     detectedBlobDescriptor.getNormalizedHistogram(),     referenceBlobDescriptor.getNormalizedHistogram(),     HISTOGRAM_COMPARISON_METHOD);     // Calculate the keypoint matching distance.   float keypointMatchingDistance = 0.0f;   std::vector<cv::DMatch> keypointMatches;   descriptorMatcher->match(     detectedBlobDescriptor.getKeypointDescriptors(),     referenceBlobDescriptor.getKeypointDescriptors(),     keypointMatches);   for (const cv::DMatch &keypointMatch : keypointMatches) {     keypointMatchingDistance += keypointMatch.distance;   }     return histogramDistance * HISTOGRAM_DISTANCE_WEIGHT +     keypointMatchingDistance * KEYPOINT_MATCHING_DISTANCE_WEIGHT; } That is the end of the blob classifier's code. Again, we see that a single class can provide useful, general-purpose computer vision functionality without a terribly complicated implementation. Perhaps this is a Zen moment; our previous work and studieshave been a path to (some kind of) simplicity! Of course, OpenCV hides a lot of complexity for us in its implementations of histogram-related functions and keypoint-related classes, and in this way, the library offers us a relatively gentle path. For completeness, note that the BlobDescriptor class has a straightforward implementation. Create a new file, BlobDescriptor.cpp, and fill it with the following bodies for a constructor and getters: #include "BlobDescriptor.h"   BlobDescriptor::BlobDescriptor(const cv::Mat &normalizedHistogram, const cv::Mat &keypointDescriptors, uint32_t label) : normalizedHistogram(normalizedHistogram) , keypointDescriptors(keypointDescriptors) , label(label) { }   const cv::Mat &BlobDescriptor::getNormalizedHistogram() const {   return normalizedHistogram; } const cv::Mat &BlobDescriptor::getKeypointDescriptors() const {   return keypointDescriptors; } uint32_t BlobDescriptor::getLabel() const {   return label; } Summary Now, we have finished all the code for the detector, descriptor, and classifier! Again, for more information, refer to Chapter 5, Classifying Coins and Commodities in the book,iOS Application Development with OpenCV 3. Resources for Article: Further resources on this subject: Making subtle color shifts with curves [article] New functionality in OpenCV 3.0 [article] Camera Calibration [article]
Read more
  • 0
  • 0
  • 9100
article-image-profiling-app
Packt
24 Apr 2015
9 min read
Save for later

Profiling an app

Packt
24 Apr 2015
9 min read
This article is written by Cecil Costa, the author of the book, Swift Cookbook. We'll delve into what profiling is and how we can profile an app by following some simple steps. It's very common to hear about issues, but if an app doesn't have any important issue, it doesn't mean that it is working fine. Imagine that you have a program that has a memory leak, presumably you won't find any problem using it for 10 minutes. However, a user may find it after using it for a few days. Don't think that this sort of thing is impossible; remember that iOS apps don't terminate, so if you do have memory leaks, it will be kept until your app blows up. Performance is another important, common topic. What if your app looks okay, but it gets slower with the passing of time? We, therefore, have to be aware of this problem. This kind of test is called profiling and Xcode comes with a very good tool for realizing this operation, which is called Instruments. In this instance, we will profile our app to visualize the amount of energy wasted by our app and, of course, let's try to reduce it. (For more resources related to this topic, see here.) Getting ready For this recipe you will need a physical device, and to install your app into the device you will need to be enrolled on the Apple Developer Program. If you have both the requirements, the next thing you have to do is create a new project called Chapter 7 Energy. How to do it... To profile an app, follow these steps: Before we start coding, we will need to add a framework to the project. Click on the Build Phases tab of your project, go to the Link Binaries with Libraries section, and press the plus sign. Once Xcode opens a dialog window asking for the framework to add, choose CoreLocation and MapKit. Now, go to the storyboard and place a label and a MapKit view. You might have a layout similar to this one: Link the MapKit view and call it just map and the UILabel class and call it just label:    @IBOutlet var label: UILabel!    @IBOutlet var map: MKMapView! Continue with the view controller; let's click at the beginning of the file to add the core location and MapKit imports: import CoreLocation import MapKit After this, you have to initialize the location manager object on the viewDidLoad method:    override func viewDidLoad() {        super.viewDidLoad()        locationManager.delegate = self        locationManager.desiredAccuracy =          kCLLocationAccuracyBest        locationManager.requestWhenInUseAuthorization()        locationManager.startUpdatingLocation()    } At the moment, you may get an error because your view controller doesn't conform with CLLocationManagerDelegate, so let's go to the header of the view controller class and specify that it implements this protocol. Another error we have to deal with is the locationManager variable, because it is not declared. Therefore, we have to create it as an attribute. And as we are declaring attributes, we will add the geocoder, which will be used later: class ViewController: UIViewController, CLLocationManagerDelegate {    var locationManager = CLLocationManager()    var geocoder = CLGeocoder() Before we implement this method that receives the positioning, let's create another method to detect whether there was any authorization error:    func locationManager(manager: CLLocationManager!,       didChangeAuthorizationStatus status:          CLAuthorizationStatus) {            var locationStatus:String            switch status {            case CLAuthorizationStatus.Restricted:                locationStatus = "Access: Restricted"               break            case CLAuthorizationStatus.Denied:                locationStatus = "Access: Denied"                break            case CLAuthorizationStatus.NotDetermined:                locationStatus = "Access: NotDetermined"               break            default:                locationStatus = "Access: Allowed"            }            NSLog(locationStatus)    } And then, we can implement the method that will update our location:    func locationManager(manager:CLLocationManager,      didUpdateLocations locations:[AnyObject]) {        if locations[0] is CLLocation {            let location:CLLocation = locations[0] as              CLLocation            self.map.setRegion(              MKCoordinateRegionMakeWithDistance(            location.coordinate, 800,800),              animated: true)                       geocoder.reverseGeocodeLocation(location,              completionHandler: { (addresses,              error) -> Void in                    let placeMarket:CLPlacemark =                      addresses[0] as CLPlacemark                let curraddress:String = (placeMarket.                  addressDictionary["FormattedAddressLines"                  ] as [String]) [0] as String                    self.label.text = "You are at                      (curraddress)"            })        }    } Before you test the app, there is still another step to follow. In your project navigator, click to expand the supporting files, and then click on info.plist. Add a row by right-clicking on the list and selecting add row. On this new row, type NSLocationWhenInUseUsageDescription as a key and on value Permission required, like the one shown here: Now, select a device and install this app onto it, and test the application walking around your street (or walking around the planet earth if you want) and you will see that the label will change, and also the map will display your current position. Now, go back to your computer and plug the device in again. Instead of clicking on play, you have to hold the play button until you see more options and then you have to click on the Profile option. The next thing that will happen is that instruments will be opened; probably, a dialog will pop up asking for an administrator account. This is due to the fact that instruments need to use some special permission to access some low-level information. On the next dialog, you will see different kinds of instruments, some of them are OS X specific, some are iOS specific, and others are for both. If you choose the wrong platform instrument, the record button will be disabled. For this recipe, click on Energy Diagnostics. Once the Energy Diagnostics window is open, you can click on the record button, which is on the upper-left corner and try to move around—yes, you need to keep the device connected to your computer, so you have to move around with both elements together—and do some actions with your device, such as pressing the home button and turning off the screen. Now, you may have a screen that displays an output similar to this one: Now, you can analyze who is spending more energy on you app. To get a better idea of this, go to your code and replace the constant kCLLocationAccuracyBest with kCLLocationAccuracyThreeKilometers and check whether you have saved some energy. How it works... Instruments are a tool used for profiling your application. They give you information about your app which can't be retrieved by code, or at least can't be retrieved easily. You can check whether your app has memory leaks, whether it is loosing performance, and as you can see, whether it is wasting lots of energy or not. In this recipe we used the GPS because it is a sensor that requires some energy. Also, you can check on the table at the bottom of your instrument to see that Internet requests were completed, which is something that if you do very frequently will also empty your battery fast. Something you might be asking is: why did we have to change info.plist? Since iOS 8, some sensors require user permission; the GPS is one of them, so you need to report what is the message that will be shown to the user. There's more... I recommend you to read the way instruments work, mainly those that you will use. Check the Apple documentation about instruments to get more details about this (https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Introduction/Introduction.html). Summary In this article, we looked at all the hows and whats of profiling an app. We specifically looked at profiling our app to visualize the amount of energy wasted by our app. So, go ahead to try doing it. Resources for Article: Further resources on this subject: Playing with Swift [article] Using OpenStack Swift [article] Android Virtual Device Manager [article]
Read more
  • 0
  • 0
  • 8841

article-image-making-your-iad
Packt
17 Feb 2012
6 min read
Save for later

Making Your iAd

Packt
17 Feb 2012
6 min read
Getting iAd Producer iAd Producer is the tool that allows us to assemble great interactive ads with a simple drag-and-drop visual interface. Download and install iAd Producer on your Mac, so that you can start creating an ad. Time for action – installing iAd Producer To install iAd Producer, follow these steps: To download and use iAd Producer, you need to be a paid member of the iOS Developer Program. Go to https://developer.apple.com/ios/ and click on the Log in button. Enter your Apple ID and password, and click on Sign In. After you've signed in, find the Downloads section at the bottom of the page. Click on iAd Producer to start downloading it. You can see the download highlighted here: If you cannot see iAd Producer in the Downloads, make sure you're logged in and your developer account has been activated. After the download is complete, open the file and run iAd Producer.mpkg to start the installation wizard. Follow the steps in the installation and enter your Mac password, if asked for it. When installing certain software, you need to enter your Mac password to allow it to have privileged access to your system. Don't confuse this with your Apple ID that we set up for the iOS Developer Program. If you don't have a password on your Mac, just leave the password area blank and click on OK. When you've gone through the installation steps it'll take a couple of moments to install. After you get a The installation was successful message you can close the installer. What just happened? We now have iAd Producer installed; whenever you need to open it, you can find it in the Applications folder on your Mac. Working with iAd Producer Let's take a look at some of the main parts of iAd Producer that you'll be using regularly, to familiarize yourself with the interface. Launch screen When you first open iAd Producer, you'll be able to start a new iPhone or iPad project from the project selector, as shown in the following screenshot. As the screen size and experience is so different between the two devices, we have to design and build ads specifically for each one: From the launch screen, you can also open existing projects you've been working on. Default ad Once you have chosen to create either an iPad or iPhone iAd, a placeholder ad is created for you, showing the visual flow. This is the overview of your ad, which you'll be using to piece the sections of your ad together. The following screenshot shows the default overview: Double-clicking on any of the screens in your ad flow will ask you to pick a template for that page; once assigned, you're then able to design the iAd using the canvas editor. Template selector Before we edit any page of an ad, we have to apply a template to it, even if it's just a blank canvas to build upon. iAd Producer automatically shows the relevant templates to the current page you're editing. This means your ad follows a structure that the users expect. Templates provide some great starting points for your iAd, whether it's for a simple banner with an image and text or a 3D image carousel that the user can flick and manipulate, all created with easy point and click. The following screenshot is an example of the template chooser: Asset Library The Asset Library holds all the media and content for your iAd, such as the images, videos, and audio. When adding media to your Asset Library, make sure you're using high-resolution images for the high-resolution Retina display. iAd Producer automatically generates the lower-resolution images for your ad, whenever you import resources. If you wanted an image to be 200px wide and 300px high, you should double the horizontal and vertical pixels to 400px wide and 600px high. This will mean your graphics look crisp and awesome on the high-resolution screens. The following screenshot shows an example of media in the Asset Library: Ad canvas Once you've selected a template, you can double-click on the item in the Overview to open up the canvas for that page. The ad canvas is where you customize your iAd with a powerful visual editor to manipulate each page of your ad. Here's an example of the ad canvas with a video carousel added to it: Setting up your ad Let's create and save an empty project to use as we create our iAd; you'll only need to do this once for each ad. Whenever you're working with something digital, it's important to save your iAd whenever you make a significant change, in case iAd Producer closes unexpectedly. Try to get into the habit of saving regularly, to avoid losing your ad. Time for action – creating a new project In order to create a new project, follow the ensuing steps: If you haven't created a new project already, open iAd Producer from your Applications folder. Select the iPhone from the launch screen and choose Select. You'll now see the default ad overview. iAd Producer has automatically made us a project called Untitled and populated it with the default set of pages. From the File menu, select Save to save your empty iAd, ready to have the components added to it later. Name the project something like Dino Stores, as that is the ad we'll be working on. You can now save the progress of your project at any time by choosing File then Save from the menu bar or pressing Command + S on your keyboard. What just happened? You've now seen the project selector and the launch screen in action, and have the base project that we'll be building upon as we make our first iAd. If you quit this project you can now open the project from within iAd Producer by clicking on File | Open, from the menu bar; or, simply double-click the project file in Finder to automatically open it. Getting the resources In this article, we'll be using the Dino Stores example resources that are available to download with this book. If you want to use your own assets, you'll need the following media: An image for your banner, approximately 120px wide and 100px high An image of your company logo or name, around 420px wide and 45px high An 80px square image, with transparency, to be used as a map pin A loading image, approximately 600px wide and 400px high Between six and 10 images for a gallery, each around 304px wide and 440px high Two or more images that will change when the iPhone is shaken, each around 600px wide and 800px high An image related to your product or service, at least 300px wide, to use on the main menu page These pixel sizes are at double-size to account for the high-resolution Retina display found on the iPhone 4 and later. iAd Producer will automatically create the lower-resolution versions for older devices.
Read more
  • 0
  • 0
  • 8819
Modal Close icon
Modal Close icon