Buyers Guide for macOS & iOS in the Enterprise

This article is more of a productivity article aimed at getting first time users up and running quickly on their Mac, iPhones or iPads. Anyone looking to buy one of these products or Tech Support teams that help employees with their computers would find this article helpful. The thoughts shared here are personal, readers are welcome to share their own thoughts and experiences.

The article is not a comprehensive guide. Its aim is to give potential users some idea as to how the devices can be used in their work environment. Specifically from an Application perspective.

Macintosh

macFamily


Which one to buy?

This depends on how the device is going to be used. Here are 3 general classifications:

Basic Usage

Basic usage would mean simple day to day tasks. These are the tasks that would qualify for:

  • Checking emails
  • Browsing the web
  • Social Media
  • Listening to Music
  • Watching Movies
  • Composing letters
  • Preparing Presentations & running presentations
  • Note taking

In such a case you may want to consider buying a MacBook or a MacBook Air. If portability is not required then a Mac Mini would also do.

At entry level configurations these devices would do the job very well.

Intermediate Usage

If the tasks being performed are a little more demanding then you may want to consider higher configuration devices. Again in most cases the  MacBook or a MacBook Air would do. If portability is not required then a Mac Mini would also do. In all these cases consider one with slightly higher configuration.

For situations where the compute power is important you may even consider the MacBook Pro. For example, if there are programmers who need to work with a high configuration Mac and they need portability, then you can consider the MacBook Pro.

Pro Usage

This indicates that the tasks being performed are very compute intensive. These are some of the job profiles which may demand compute intensive resources:

  • Programmers
  • Video Editors
  • Audio Editors
  • Post Production Teams
  • Marketing & Creative Teams
  • Scientific Research

For such situations the higher end desktops & MacBook Pros would be required. So the iMac or the highest configuration Mac Mini, or the 15″ MacBook Pro would be best suited for such environments.

In some situations even more powerful computers would be required. The iMac Pro & Mac Pro should then be considered.


Built In Applications that might be useful

Productivity Tools

There are 3 applications which are a part of the suite called iWork that are very useful in organisations.

  • PAGES: Built in word processing application. You can easily created documents, letters, reports and even have them exported in Microsoft Office compatible format.
  • KEYNOTE: Built in presentation applications. Enables you to create powerful presentations from scratch. Like Pages it is possible to create presentations that are compatible with PowerPoint.
  • NUMBERS: Built in spreadsheet application. Enables you to quickly create spreadsheets and export them to Excel if needed.

The other advantage is the fact that these applications are also accessible from the cloud. Tight integration with iCloud means that you can make changes to documents from your Mac, iPhone, iPad, or iCloud.com.

Creative Tools

There are 2 applications which are available for creative purpose. These might be handy for people working in the creative departments.

  • IMOVIE: Quick create movies using videos, audios and photos that you have.
  • GARAGEBAND: A simple Music creation application that comes with a library of different instruments.

Popular Third Party Applications

These are just some of the applications.

Office Suite

Productivity

Cloud

Creative

Security

Communication

Data Backup

Virtualisation (Running Windows or Windows Applications on the Mac)


Some tasks that can be done with built in Applications

  • Scanning Documents using Preview
  • Signing Documents using Preview
  • Record Screen Activity using QuickTime
  • Record a quick movie using QuickTime
  • Automate Tasks & create workflows using Automator
  • Encrypt Data using FileVault
  • Show your iPhone/iPad screen on a projector using QuickTime on Mac
  • Backup data using Time Machine

iPhone/iPad

iosFamily


Which one to buy?

The decision on whether to buy the iPhone &/or the iPad depends a lot on what you intend to use it for. As such the major differences between the 2 devices are:

  • iPads tend to have larger screens
  • iPhone has cellular communication capability
  • iPhones are more portable as compared to iPads
  • iPads are better suited for long duration usage
  • iPads tend to be higher powered devices

While it appears that iPads are better than iPhones, that is not necessarily the case. iPhones being smaller and more compact have many advantages too.

Ideally speaking having both, an iPhone and an iPad, is the best thing to do.

To make a decision use the task list below to help find out if you need an iPhone or an iPad or both.

Note, even though I mention that the tasks can be performed easily on an iPhone, many of the tasks can also be done very easily on the iPad. The point is to illustrate ease of use in situations where you have to perform tasks with a single hand or when you are on the move.

Tasks easily performed on an iPhone

  • Making calls
  • Messaging
  • Scheduling activities such as: Reminders, Appointments, Events
  • Taking Photos & Videos
  • Emails
  • Banking Transactions
  • Finding Transit Directions
  • Finding a Taxi
  • Making E-Payments

Tasks easily performed on the iPad

  • Writing letters & blogs
  • Creating Presentations
  • Working with spreadsheets
  • Creating posters, flyers
  • Working with business applications
  • Content creation

If you do a mixture of tasks from both the lists then getting both an iPhone as well as an iPad is a good idea.

A thing to keep in mind is that the Pro version of the iPad also has a nice keyboard accessory as well as the  Pencil available. These 2 products make the whole experience so much better.

Screen size consideration

iPhone and iPad screen sizes vary quite a bit. Here are some tips on the tasks which can be best performed on specific screen sizes.

Creative Work

Generally speaking, creative tasks require a large screensize. So for an iPhone the smallest screen you should have is 4.7″. Similarly for the iPad the smallest screen you should have is the  9.7″.

Documents, letters, spreadsheets

These tasks are better performed on the iPads as such you can go for any screen size in them. Of the lot, its a lot easier to create documents and letters on the phone than spreadsheets. Again, for phones one should the larger the screen size the better.

Presentations

Like documents and spreadsheets presentations are a lot easier to create on the iPad. They can also be created from the phones. The larger the phone the better.

Messaging & Communication

This is one aspect where the screen size is not so much of an issue. In fact, some users may find the smaller screen size a lot better. Typically, the iPhone is a much better device than the iPad for this.

Productivity & General Tasks

This includes calling taxis, ordering food, taking notes, control keynote presentations, setting up appointments and reminders. These tasks are also best performed on iPhones. They can be done well with the iPad too.


Built In Applications that might be useful

Productivity Tools

There are 3 applications which are a part of the suite called iWork that are very useful in organisations.

  • PAGES: Built in word processing application. You can easily created documents, letters, reports and even have them exported in Microsoft Office compatible format.
  • KEYNOTE: Built in presentation applications. Enables you to create powerful presentations from scratch. Like Pages it is possible to create presentations that are compatible with PowerPoint.
  • NUMBERS: Built in spreadsheet application. Enables you to quickly create spreadsheets and export them to Excel if needed.

The other advantage is the fact that these applications are also accessible from the cloud. Tight integration with iCloud means that you can make changes to documents from your Mac, iPhone, iPad, or iCloud.com.

Creative Tools

There are 2 applications which are available for creative purpose. These might be handy for people working in the creative departments.

  • IMOVIE: Quick create movies using videos, audios and photos that you have.
  • GARAGEBAND: A simple Music creation application that comes with a library of different instruments.

Other Apps

  • Notes
  • Voice Memos
  • Files

Popular Third Party Applications

Office Suite

Productivity

Cloud

Creative

Security

Communication


Some tasks that can be done with built in Applications

  • Scanning Documents using Notes
  • Recording Voice Memos
  • Control HomeKit devices
  • Edit PDFs through iBooks
  • Create PDF documents through pages & then edit the PDFs either through iBooks or markup utilities
  • Record and Edit videos using the camera & iMovie

Useful iPad Accessories

 TV

There are a few things that can be done with the  TV. It can be used to mirror both macOS & iOS Devices. In which case apps such as Reflector are not really required.

It is very easy to setup and use. This can make projecting both the iPad screen as well as the iOS Screen very easy & it allows you to move across the room as you are not physically wired to the projector.

Final Word

As we can see there are a wide variety of apps available both for macOS & iOS. These include built in apps as well as Third party apps. The community of developers creating these apps is strong and growing. There are many more apps which can be used for a wide variety of purposes.

This article should give the user a fair idea as to the capabilities of devices such as iPads, MacBooks and the rest of the line up. The good thing is that for enterprise environments its easily possible to create apps that are tailored to the needs of that organisation and this makes the devices much more attractive.

Adding formatted text to Swift in Xcode

Formatting in Playgrounds and Xcode projects is achieved using Markups in comments. The following article describes some of the things that you can do. Note that there are many more ways of acheiving some of the effects shown here.

The idea behind markups is to make your code more readable whether you are using Playgrounds or Xcode.

If you can only see the commented code in playgrounds and not the rendered markup then click on Editor > Show Rendered Markup to view the rendering. You can use this option to toggle back and forth.

Formatting in Playgrounds

Plain Text

There are different kinds of text you can place in a Playground. Let us look at the code below to see what all is achieved.

//: # Documentation
//: ## Contents
//: * Text Description
//: * Documentation for Functions
//: * Documentation for Types
//: * Formatting Text
//:  - Code
//:  - Italics
//:  - Bold
//: * Inserting Items
//: * Links
//: * Assets
//: * Callouts

The comments here are in the format //:.

Rendered Output

This is how the rendered output looks.

Line 1 shows how to render a Title Text. This is achieved using the # before the text.
Line 2 shows how to get a lower sized text by using ## instead of #. We can achieve more levels if we wish.

For multi line text with bullets use the *, +, – symbols. This is seen on lines 7-13.

It is also possible to create numbered lists too. Simply type the numbered list & it renders accordingly.

//: * Inserting Items
//: 1. Links
//: 2. Assets
//: 3. Callouts

This renders as:

Screen Shot 2017-11-08 at 11.25.27 AM

Playground Pages

It is possible to have multiple pages in Playgrounds. This way we can create a more readable experience that makes the code structured, compartmentalised and easier to understand.

To do that open a playground and then simply add a playground by clicking File > New > Playground Page.

To move from one page to the next simply write the comment.

//: [Next Topic](@next)

This will automatically place a link to jump to the next page.

Similarly you can add a link to move to the previous page.

//: [Previous](@previous)

Code block

We can even show a code block in the text. It is formatted in a different manner to tell the user that it is a code block.

//: ### Code block
/*:
Loop to print characters
````
for char in "Arun Patwardhan"
{
    print(char)
}
*/

This is how it appears:

Screen Shot 2017-11-08 at 11.30.45 AM

Function Help

There is also some formatting that can be done for functions, types and other pieces of code written in a playground. This also appears on the quick help of the sidebar.

We will look at how to create formatted markup for playgrounds.

/*:
## This function takes temperature in Centigrade and converts it to Fahrenheit.
- important: This function does not do data validation
*/
/*:
- Note: "Please refer to Quick Help for more information."
*/
/*:
- Callout(Custom Callout): This is how you create a custom callout ` - Callout(Custom Callout):`
*/
/*:
- Example: `convert_to_fahrenheit_from(Centigrade: 32.0)`
*/

This renders as:

Formatted Markup for Functions

Formatted Markup for Functions.

We will look at formatting the comments to appear in Quick Help in the Formatting for Xcode section.

Inserting Links

The last bit is related to inserting links. We have already seen how to insert links for moving between Playground pages.

Redirecting to URL

/*:
For more articles on Programming, see [Programming articles @ arunpatwardhan.com](https://arunpatwardhan.com/category/programming/)
*/

This renders as:

Screen Shot 2017-11-09 at 11.14.24 AM

Formatting for Xcode

Function Help

As we saw in the earlier section we can create a lot of documentation for Functions. The approach is similar to the one we used in Playgrounds. We will be using callouts to provide information. We will use some callouts for Playgrounds, however, there are many more callouts available for Xcode Symbol Documentation as compared to Playground. The main difference here is the fact that the comments begin with /** instead of /*:.

“The code shown below will work in both, regular Xcode projects as well as Playgrounds.”

/**
This function takes temperature in Centigrade and converts it to Fahrenheit.
- important: This function does not do data validation
- parameter temp: This is the temperature in Centigrade. It can be a negative value too.
- returns: This is the temperature in Fahrenheit.
- requires: `temp > -273.0 && temp < 1000.0` - Note: The requirement mentioned is not enforced. - Since: iOS 11 - author: Arun Patwardhan - copyright: Copyright (c) Amaranthine 2015 - version: 1.0 */
func convert_to_fahrenheit_from(Centigrade temp : Float) -> Float
{
    return ((temp * 9.0 / 5.0) + 32.0)
}

This renders as:

Formatted Markup for Playgrounds as well as Quick Help

Formatted Markup for Playgrounds as well as Quick Help

Note that the quick help appears in the Right hand side sidebar. That too only after you select the function.

As we can see this makes the function a lot more readable. The real advantage of Quick Help comes in the fact that the documentation is now easily accessible no matter which file we are in within the project. The also helps the developer put in the right kind of information, required for proper usage of the function, in the help section.

Note that the rendered markup for Playgrounds will only appear in Playgrounds. 

Inserting Links

Just like in the previous section where we introduced links we can add links to the symbol documentation.

/**
   For more articles on Programming [Programming articles @ arunpatwardhan.com (https://arunpatwardhan.com/category/programming/)
*/
func recursiveFunction(count : inout Int)
{
   while 0 <= count
   {
      count -= 1
      recursiveFunction(count: &count)
   }
}

This renders in Quick Help as:

Screen Shot 2017-11-09 at 11.26.53 AM

Callouts supported by Playgrounds

  • Custom Callout
  • Example

Callouts supported by Symbol Documentation

  • Attention
  • Author
  • Authors
  • Bug
  • Complexity
  • Copyright
  • Date
  • Invariant
  • Precondition
  • Postcondition
  • Remark
  • Requires
  • See Also
  • Since
  • Version
  • Warning

Callouts supported by both Playgrounds & Symbol Documentation

  • Experiment
  • Important
  • Note

Programming Style Guide: Code Refactoring

One of the key attributes towards code that is readable and easy on the eyes is code that is split into appropriately sized pieces. Code refactoring is does exactly that. It is very easy to write a program as one big piece of code. Of course, any program that grows becomes increasingly complicated and highly inefficient. If not controlled, it will soon reach a point where it is highly unreadable, extremely difficult to maintain & filled with bugs. Not to mention that it is inefficient too.

Refactoring code and breaking it down into smaller reusable chunks is the key. The objective is:

  1. To make code easier to read
  2. To make reusable components so that we can save on duplication of code. This will reduce the code count and make sure that any changes to the reused code are available everywhere.
  3. To lend a structure to the application. Tasks now have their own space.
  4. Build scalable and maintainable code.
  5. Build bug free code.

Let us look at an example.

Screen Shot 2017-10-16 at 11.26.26 AM

Bad Code

This code is clearly written poorly. Its difficult to read. There aren’t good whitespaces. No consistency. Even the naming conventions are poor.

The fix would be :

  • Break it down into different functions
  • Separate tasks into their own files
  • Name the different elements of the code properly.

This is how the code looks now. It has been broken down into different files.

main.cpp

#include <iostream>
#include "MathOperations.hpp"
#include "Choices.hpp"

int main(int argc, const char * argv[])
{
     float number1           = 0.0;
     float number2           = 0.0;
     Choices selectedOption  = CLEAR;
     float answer            = 0;
     float integralAnswer    = 0;

     while(EXIT != selectedOption)
     {
          //Welcome message
          std::cout<<"Welcome to Calculator Program"<<std::endl;
          std::cout<<"Choose between the following options"<<std::endl;
          std::cout<<"1. Add\n2. Subtract\n3. Multiply\n4. Divide\n5. Remainder\n6. Percentage"<<std::endl;

          //User choice
          std::cout<<"Choice: ";                               std::cin>>selectedOption;

          //Chance to enter first number
          std::cout<<"Number 1: ";                               std::cin>>number1;

          //Chance to enter second number
          std::cout<<"Number 2: ";                               std::cin>>number2;

          switch (selectedOption)
          {
               case ADDITION:
                    answer = addition(number1, number2);
                    std::cout<<"The addition of "<<number1<<" & "<<number2<<" = "<<answer<<std::endl;
                    break;
               case SUBTRACTION:
                    answer = subtraction(number1, number2);
                    std::cout<<"The subtraction of "<<number1<<" & "<<number2<<" = "<<answer<<std::endl;
                    break;
               case MULTIPLICATION:
                    answer = multiplication(number1, number2);
                    std::cout<<"The multiplication of "<<number1<<" & "<<number2<<" = "<<answer<<std::endl;
                    break;
               case DIVISION:
                    answer = division(number1, number2);
                    std::cout<<"The division of "<<number1<<" & "<<number2<<" = "<<answer<<std::endl;
                    break;
               case REMAINDER:
                    integralAnswer = remainder((int)number1, (int)number2);
                    std::cout<<"The remainder of "<<number1<<" divided by "<<number2<<" = "<<integralAnswer<<std::endl;
                    break;
               case PERCENTAGE:
                    answer = percentage(number1, number2);
                    std::cout<<"The percentage of "<<number1<<" out of "<<number2<<" = "<<answer<<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span><std::endl;
                    break;
               default:
                    break;
          }
     }
     return 0;
}

Choices.hpp

#ifndef Choices_hpp
#define Choices_hpp

#include <stdio.h>
#include <iostream>

enum Choices : unsigned short int { ADDITION = 1, SUBTRACTION, MULTIPLICATION, DIVISION, REMAINDER, PERCENTAGE, CLEAR, EXIT};

typedef enum Choices Choices;

std::istream& operator >>(std::istream &is, Choices& enumVar);

#endif

Choices.cpp

#include "Choices.hpp"

std::istream& operator >>(std::istream &is, Choices& enumVar)
{
    unsigned short int intVal;
    is>>intVal;
    switch (intVal) {
        case 1:
            enumVar = ADDITION;
            break;
        case 2:
            enumVar = SUBTRACTION;
            break;
        case 3:
            enumVar = MULTIPLICATION;
            break;
        case 4:
            enumVar = DIVISION;
            break;
        case 5:
            enumVar = REMAINDER;
            break;
        case 6:
            enumVar = PERCENTAGE;
            break;
        default:
            enumVar = EXIT;
            break;
    }
    return is;
}

MathOperations.hpp

#ifndef MathOperations_hpp
#define MathOperations_hpp

#include <stdio.h>

//Addition
float addition(float number1, float number2);

//Subtraction
float subtraction(float number1, float number2);

//Multiplication
float multiplication(   float number1, float number2);

//Division
float division(float number1, float number2);

//Remainder
int remainder(int number1, int number2);

//Percentage
float percentage(float number1, float number2);

#endif

MathOperations.cpp

#include "MathOperations.hpp"

//Addition
float addition(float number1, float number2)
{
    return number1 + number2;
}

//Subtraction
float subtraction(float number1, float number2)
{
    return number1 - number2;
}

//Multiplication
float multiplication(   float number1, float number2)
{
    return number2 * number1;
}

//Division
float division(float number1, float number2)
{
    if (number2 > 0) {
        return number1 / number2;
    }
    return 0.0;
}

//Remainder
int remainder(int number1, int number2)
{
    return number1 % number2;
}

//Percentage
float percentage(float number1, float number2)
{
    if (number2 > 0) {
        return (number1 / number2) * 100.0;
    }
    return 0.0;
}

Let us look at how this looks for Swift.
main.swift

import Foundation

var number1 : Float             = 0.0
var number2 : Float             = 0.0
var selectedOption : Choices    = Choices.CLEAR
var answer : Float              = 0.0
var integralAnswer : Int        = 0

func readNumbers(One firstNumber : inout Float, Two secondNumber : inout Float)
{
     //Chance to enter first number
     print("Number 1: \n")
     firstNumber = Choices.inputNumbers()

     //Chance to enter second number
     print("Number 2: \n")
     secondNumber = Choices.inputNumbers()
}

while(Choices.EXIT != selectedOption)
{
     //Welcome message
     print("Welcome to Calculator Program")
     print("Choose between the following options")
     print("1. Add\n2. Subtract\n3. Multiply\n4. Divide\n5. Remainder\n6. Percentage")

     //User choice
     print("Choice: \n")
     selectedOption = Choices.inputChoices()
     switch (selectedOption)
     {
          case Choices.ADDITION:
               readNumbers(One: &number1, Two: &number2)
               answer = addition_of(_value: number1, with_value: number2)
               print("The addition of \(number1) & \(number2) = \(answer)")
               break
          case Choices.SUBTRACTION:
               readNumbers(One: &number1, Two: &number2)
               answer = subtraction_of(_value: number1, from_value: number2)
               print("The subtraction of \(number1) & \(number2) = \(answer)")
               break
          case Choices.MULTIPLICATION:
               readNumbers(One: &number1, Two: &number2)
               answer = multiplication_of(_value: number1, with_value: number2)
               print("The multiplication of \(number1) & \(number2) = \(answer)")
               break
          case Choices.DIVISION:
               readNumbers(One: &number1, Two: &number2)
               answer = division_of(_value: number1, by_value: number2)
               print("The division of \(number1) & \(number2) = \(answer)")
               break
          case Choices.REMAINDER:
               readNumbers(One: &number1, Two: &number2)
               integralAnswer = remainder_of(_value: Int(exactly:number1)!, <span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>divided_by_value: Int(exactly: number2)!)
               print("The remainder of \(number1) divided by \(number2) = \(integralAnswer)")
               break
          case Choices.PERCENTAGE:
               readNumbers(One: &number1, Two: &number2)
               answer = percentage_of(_value: number1, with_respect_to_value: number2)
               print("The percentage of \(number1) out of \(number2) = \(answer)")
               break
          default:
               selectedOption = .EXIT
               break
     }
}

Choices.swift

import Foundation

enum Choices { case ADDITION, SUBTRACTION, MULTIPLICATION, DIVISION, REMAINDER, PERCENTAGE, CLEAR, EXIT}

//CLI Reading Capability
extension Choices
{
    static func inputChoices() -> Choices
    {
        let ip : String? = readLine()
        let choice : String = String(ip!)

        switch choice {
        case "1":
            return .ADDITION
        case "2":
            return .SUBTRACTION
        case "3":
            return .MULTIPLICATION
        case "4":
            return .DIVISION
        case "5":
            return .REMAINDER
        case "6":
            return .PERCENTAGE
        default:
            return .EXIT
        }
    }

    static func inputNumbers() -> Float
    {
        let ip : String? = readLine()

        let numberFormatter = NumberFormatter()
        let number = numberFormatter.number(from: ip!)

        let num : Float? = number?.floatValue
        return num!
    }
}

MathOperations.swift

import Foundation

//Addition
func addition_of(_value number1 : Float, with_value number2 : Float) -> Float
{
    return number1 + number2;
}

//Subtraction
func subtraction_of(_value number2 : Float, from_value number1 : Float) -> Float
{
    return number1 - number2;
}

//Multiplication
func multiplication_of(_value number1 : Float, with_value number2 : Float) -> Float
{
    return number2 * number1;
}

//Division
func division_of(_value number1 : Float, by_value number2 : Float) -> Float
{
    if (number2 > 0) {
        return number1 / number2;
    }
    return 0.0;
}

//Remainder
func remainder_of(_value number1 : Int, divided_by_value number2 : Int) -> Int
{
    return number1 % number2;
}

//Percentage
func percentage_of(_value number1 : Float, with_respect_to_value number2 : Float) -> Float
{
    if (number2 > 0) {
        return (number1 / number2) * 100.0;
    }
    return 0.0;
}

Discussion on Swift Extensions

As we can see that most of the code in Swift is very similar to C++. Most of the differences are basic syntactic differences. However, there is 1 feature of Swift that greatly aids code refactoring that I would like to talk about, Extensions.

Extensions allow us to add new functionality to the existing type. As the name says the type is extended. This allows us to add changes to a type in a consistent & clearly demarcated way. Developers can now neatly separate newly added components. This greatly helps in understanding the evolution of types.

“This is often referred to as versioning.”

Extensions can be used in the following ways to implement code refactoring:

  • Different sections of a type reside in their own extensions
  • Changes made to a type are made by keeping them in their own extensions
  • Step by step build up of code is done by representing each step as an independent extension. This gives clarity on how a certain end result was achieved.

Conclusion

As we can see from the sample code above (for both C++ & Swift) the program is much more readable. Code is carefully compartmentalised. Its a lot easier to read. It is a lot easier to scale too.

The reader may point out that the amount of code to achieve the same result is significantly higher, that however is a small price to pay in the long run. The biggest advantage is the scalability & the ease with which it can be done. Simply breaking code down into separate files & functions makes a huge difference. Here are some other benefits:

  • Individual files can be modified. This means one can now have a team working on different parts of the code.
  • Code is less cluttered. Changes are now spread across files & are easier to track.

We will now see how we can further improve this code in upcoming articles.

COLLECTION TYPE, SEQUENCE TYPE & INDEXABLE TYPE – Update

This is an update to the topic covered earlier. You can read about the Protocols in detail in the original article. Collection Type, Sequence Type & Indexable Type

Most of the things are the same here are some of the changes:

  1. The Indexable protocol is now not necessarily required. All the aspects of the indexable protocol now fall under the Collection Protocol
  2. The names of the protocols have changed from SequenceType & CollectionType to Sequence & Collection
  3. The keyword Generator has been renamed to Iterator. Accordingly the generate function has been renamed makeIterator function.
  4. The collection protocol now requires the implementation of the function index, this function returns the value of the next index.

The sample code below should clarify

class CustomStack
{
    var data : [Element] = [Element]()

    func push(Element newElement : Element)
    {
        data.append(newElement)
    }

    func pop() -> Element
    {
        return data.removeLast()
    }
}

//Additional Implementations - not strictly required
extension CustomStack
{
    typealias Index = Int

    var startIndex : Index
    {
        return 0
    }

    var endIndex: Index
    {
        return (data.count - 1)
    }

    subscript (position : Index) -> Element
    {
        return data[position]
    }
}

extension CustomStack : Sequence
{
    typealias Iterator = AnyIterator

    func makeIterator() -> Iterator
    {
        var index = 0
        return AnyIterator({() -> Element? in
            if index < self.data.count
            {
                let res =  self.data[index]
                index += 1
                return res
            }
            return nil
        })
    }
}

extension CustomStack : Collection
{
    typealias SubSequence = CustomStack

    subscript (bounds: Range) -> CustomStack.SubSequence
    {
        let newStack : CustomStack = CustomStack()

        for i in bounds.lowerBound...bounds.upperBound
        {
            newStack.push(Element: data[i])
        }
        return newStack
    }

    /// Returns the position immediately after the given index.
    /// - Parameter i: A valid index of the collection. `i` must be less than
    ///   `endIndex`.
    /// - Returns: The index value immediately after `i`.
    func index(after i: Int) -> Int
    {
        if i < endIndex
        {
            return i + 1
        }
        return i
    }
}

When to use Swift & when to use Objective-C?

Over the past few years I have received a number of questions with regards to Swift & Objective-C. Specifically related to the future of the 2. I will try to address those questions in the form of an FAQ.

Should I learn Swift or Objective-C?

This is a question that I get from developers new to iOS/macOS App Development. Ideally speaking, you should learn Swift. As that is going to become the main language for App development on Apple’s ecosystem. However, the reality is a little different. There are a large number of applications that are written in Objective-C. You are likely to encounter them at your workplace. You may also have to maintain, upgrade & improve those apps. In such a case, it makes sense to learn Objective-C too.

Can I mix Swift & Objective-C in the same project?

Yes! But remember that you should check for feature compatibility between the 2 languages. Adding Swift code to an Objective-C project may not be very beneficial as only those features that are compatible with Objective-C can be written in Swift.

Going the other way round is not a problem. You can read more about that here:Mixing Swift & Objective-C

Will Objective-C be deprecated in the future?

That is an interesting question. There is no formal announcement from Apple stating the Objective-C is going to be deprecated. However, one can expect more attention to be paid to Swift. That is where most of the newest techniques, tools & technologies are going to be available. Objective-C will keep running as it is as of now.

Can I mix Swift with other Programming Languages?

Swift can easily be mixed with Objective-C. If you wish to incorporate C++ or C code in your Swift Project then wrapping them in Objective-C code allows you to achieve this.

Apart from that Swift does support working with C code code. You can read about that here:Interacting with C APIs.

Swift does not provide interoperability support for any other languages as of now.

Which version of Swift should I use?

It is recommended that you use the latest available version of Swift. However, the actual version that you work on depends on many other factors like: compatibility with OS Versions, support & business related choices.

Why shouldn’t we just convert all our Objective-C code to Swift and keep things simple?

A very tempting proposition. However, practical realities prevent us from doing this. The process of converting from Objective-C to Swift is time consuming. Apart from having to convert the syntax, the code also needs to be optimised taking into account the new features that are available. This will mean extensive testing and quality assurance. Most companies will not invest their resources into this endeavour.

A better approach is to migrate to Swift gradually. Here are some ways to do this:

  1. If its a brand new product/app that you are creating, start it in Swift.
  2. Any new reusable code components that are being created should be done in Swift (they should be Objective-C compatible if you intend to use this code in Objective-C projects).
  3. If any part of a product is going to undergo heavy change, either due to a bug fix or a new feature. This is a good time to convert it into Swift.

A good example is how Apple is approaching the process of migrating to Swift. They are doing it component by component.

I have been developing apps in Objective-C for some time. I am able to create any reasonably complicated app now. If Objective-C hasn’t been deprecated then should I start making apps in Swift?

This is a choice that you have to make. It is recommended that new apps (at the very least) be made in Swift as that is the language that will undergo the maximum amount of changes & improvements in the future.

What do you suggest as a trainer?

Another question that I get very often. It depends on the situation. I would say learn both Swift & Objective-C. You can skip learning Objective-C if you are confident that you will not have to work with any projects written in that language.

If I am starting on a brand new project I would use Swift. But if its an Objective-C project I would stick to Objective-C.

Can Swift development only be done on macOS?

No! Swift development can also be done on Linux. However, iOS/macOS/tvOS/watchOS App Development can only be done on macOS through Xcode.

How should I migrate to Swift?

There are different approaches that one can use. It all depends on the situation and needs of your organisation. Here are some things that you can do:

  • Start development of brand new apps (from scratch) in Swift.
  • If you are creating a brand new library which will be used for future projects then go ahead with Swift.
  • If a major component of an existing app is going to be changed significantly then you can go ahead with Swift.

You can do all or some of the above. There may be other strategies too. You should also factor in the cost of migration from one language to another.

 

Collection Type, Sequence Type & Indexable Type

This is for Swift Version 2.2 & earlier. I will be adding the snippet of code for the changes the Swift 3.x have introduced.

What are the Collection Type & Sequence Type Protocols?

The Collection Type, Sequence Type & Generator Type Protocols define rules that govern how different data structures or collections of data can be used, interacted with and operated within the Swift programming language. The CollectionType is a special case of the SequenceType.

Why do we need such Protocols?

Lets take the example of the Swift For-Loop.

var arrOfStrings : [String] = [String]()

arrOfStrings.append("Jill")
arrOfStrings.append("Jack")
arrOfStrings.append("John")
arrOfStrings.append("Jane")

for name in arrOfString
{
     print("The name is \(name)")
}

Now, if we have created our own data type. We would not be able to use the above for-loop as it would not conform to the … type protocols. The for-loop is expecting a data structure that acts and behaves in a way that is governed by the … protocols.

Just like the for-loop example above there are many other features within the Swift Programming Language that expect data structures to act and behave in a particular way. By designing our data structures to conform to these protocols we can make the easily compatible with the existing code and language features out there.

How do we use these protocols for our own data structures?

First we need to decide what kind of collection are we making. For the sake of this example I will create a Custom Stack.

class CustomStack<Element>
{
    var data : [Element] = [Element]()

    func push(Element newElement : Element)
    {
        data.append(newElement)
    }

    func pop() -> Element
    {
        return data.removeLast()
    }
}

The above code is very simple for the purpose of this exercise. Its a stack. Which is internally really an Array. It has functions to push data and pop data. We are now going to convert this type to a collection to conform to the CollectionType protocol.

Implementing the Indexable Protocol methods

As a first step we are going to make our CustomStack conform to the Indexable Protocol.

extension CustomStack : Indexable
{
    //INDEXABLE PROTOCOLS
    typealias Index = Int

    var startIndex : Int
    {
        return 0
    }

    var endIndex: Int
    {
        return (data.count - 1)
    }

    subscript (position : Int) -> Element
    {
        return data[position]
    }
}

The above change makes the data structure conform to the Indexable protocol. This is a requirement for it to be of type CollectionType. In order to conform to the Indexable protocol we need to implement a few computed properties. Let us look at the changes

typealias Index = Int

This line informs the system that the Indexing type for my data structure is an Int.

var startIndex : Int
{
    return 0
}

var endIndex: Int
{
    return (data.count - 1)
}

The next 2 are computed properties. Each provides the implementation of the startIndex  and endIndex properties. Note that the type for both is Int as we have declared the Index type earlier as Int.

subscript (position : Int) -> Element
{
    return data[position]
}

The last implementation is of subscript. This provides the implementation to access an Element from the Stack using the Subscript operator.

Implementing the Sequence Type Protocol

Next we will implement the Sequence Type Protocol methods.

extension CustomStack : SequenceType
{
    typealias Generator = AnyGenerator<Element>
    
    func generate() -> Generator
    {
        var index = 0
        
        return AnyGenerator(body: {() -> Element? in
            if index < self.data.count
            {
                let res =  self.data[index]
                index += 1
                return res
            }
            return nil
        })
    }
}

Let us examine this code line by line.

typealias Generator = AnyGenerator<Element>

Objects of type Generator allow us to navigate through our collection. Quite like how iterators  work in C++. This line specifies the type to be AnyGenerator for Elements.

func generate() -> Generator

Next we start the implementation of the generate function. This is required as part of the SequenceType protocol.

var index = 0

This index variable is used to track the element that is currently being accessed.

return AnyGenerator(body: {() -> Element? in
            if index < self.data.count
            {
                let res =  self.data[index]
                index += 1
                return res
            }
            return nil
        })

The return statement is the main statement. Here we are creating an object of type AnyGenerator. As an argument to the constructor call we are passing in a closure that will be used to iterate through the sequence. Note that the closure captures the index variable and holds a reference to its value even though we have left the original function.

Implementing the Collection Type Protocol

Next we will implement the Collection Type Protocol methods. We don’t really need to implement a lot in order to conform to the CollectionType protocol. In fact, if we just conform to the CollectionType protocol and use the implementations of the previous 2 extensions we should be just fine. However, for the sake of demonstration we are implementing the subscript functionality within the CollectionType.

extension CustomStack : CollectionType
{
    typealias SubSequence = CustomStack<Element>
    
    subscript (bounds: Range<CustomStack.Index>) -> CustomStack.SubSequence
    {
        let newStack : CustomStack<Element> = CustomStack<Element>()
        
        for i in bounds.startIndex...bounds.endIndex
        {
            newStack.push(Element: data[i])
        }
        return newStack
    }
}

Let us look at the code line by line.

typealias SubSequence = CustomStack<Element>

Again, as before this line indicates that the SubSequence type is actually a CustomStack.

subscript (bounds: Range<CustomStack.Index>) -> CustomStack.SubSequence

Here we start the implementation of the subscript functionality.

let newStack : CustomStack<Element> = CustomStack<Element>()
        
for i in bounds.startIndex...bounds.endIndex
{
     newStack.push(Element: data[i])
}
return newStack

The rest of the code is the implementation of the subscript range behaviour. One can have different implementations to achieve the same result.

CollectionType Video

Conclusion

As we can see, by designing our data structure to conform to a particular set of protocols. We have made it possible for our data structure to take advantages of the different features, functionalities and even API’s available within the Swift Language and the Frameworks used as a part of iOS, macOS, watchOS & tvOS development.

Creating Frameworks for iOS/OS X App Development

Creating Swift Frameworks

Creating Swift Frameworks is easy. The steps below walk you through creating a Swift Framework. The steps below have been performed on Xcode 7.3

  1. Launch Xcode.
  2. Select Create New Project. Or from the menu bar select File > New > Project
  3. From the Template chooser select the Framework & Library  Option under iOS
  4. Select Cocoa Touch Framework1
  5. Give your project a name.
  6. Make sure the language selected is Swift.
  7. Feel free to enter values of your choice for organisation name and organisation identifier.
  8. Save your project. Optionally, if you have a version control repository like Git you may save it there.
  9. In left hand side bar make sure you have selected the Project Navigator.
  10. Within the Project Navigator make sure you have selected the folder named after your project.
  11. Click on File > New > File.
  12. Make sure iOS Source is selected on the left hand side.
  13. Select the file type as Swift.IMG_3525
  14. Write down the code that you want to make available through a framework.
  15. Now this is the key point. Place the keyword public before all the elements that you want to make publicly accessible.Why do we need to do this? To understand this we need to understand the scope of different elements within a typical Swift project. IMG_3521

    Different variables/classes/functions that are declared within a module are accessible freely within the module. Swift files contain code & are themselves found within Swift modules. So a module can mean project or a framework.So, to access the variables/functions/classes from module A in module B, we have to make those elements of module A public in order to access them in module B.

    For more information, do read Apple’s Swift Documentation.

  16. The next steps depend on what your ultimate objective is. If you wish to build a framework for distribution then you need to follow a process that is similar to distributing an app. You need to get the code signing done & prepare the project for distribution.
  17. If however, you plan to release it internally, or even just test it. Then you can follow the steps below.
  18. Firstly, our objective is to make this framework run on both OS X(macOS) as well as iOS.
  19. To do that we will be adding a new target. Click on File > New > Target.
  20. Select OS X & the Frameworks & Libraries from the sidebar.
  21. Select Cocoa Touch Framework
  22. Give your framework a unique name. Something that indicates this framework is for OS X(macOS).
  23. Now, we don’t need to rewrite the code for the Mac. We can simply make the file we have written a member for the OS X Framework Target.
  24. To do that make sure that the right hand side sidebar is visible.
  25. In the left hand side sidebar make sure that you have selected the new Swift file with the code you have written in there.
  26. In the right hand side sidebar select the Document Inspector.
  27. Under Target Membership make sure that both the Targets are checked. The target for iOS should already be checked.IMG_3520
  28. Thats it. If you do not wish to make your code available for both iOS & OS X then skip steps 19 – 27.
  29. The next part is building the framework. We will be building this framework for use internally. We will first build the iOS framework.
  30. From the tool bar, make sure the target selected is for iOS. For the device you can select any device that you wish.
  31. Then click on Product > Build to build the framework. If all goes well then you should get the message Build Succeeded on your screen.
    IMG_3519
  32. To get hold of the framework, expand the product folder from the left hand side sidebar.
  33. Select the Framework you have just built. Note that it should be black in colour. If you have opted to make a framework for OS X, then you should see that framework listed too, it should be in red colour. The red colour indicates that it has not yet been built.IMG_3524
  34. Control-click on the iOS version of the framework and select Show in Finder.
  35. This will take you directly to the folder containing the framework. Copy paste it to the desktop or to any other location to easily access it when required.
  36. Repeat steps 30 – 34 to build the OS X version of the Framework. Make sure that the target selected is OS X.
  37. Once we have done that, we need to test the framework we just created.
  38. Create a dummy iOS Project for testing.
  39. From the left hand side project navigator make sure that the blue project settings file is selected.
  40. Make sure that the Target is selected within the settings screen.
  41. Under the General tab scroll down to the Embedded Binaries section.
  42. Click on the ‘+’ sign to add a framework.IMG_3523
  43. Click on Add other
  44. Navigate to the folder where you saved the Framework and select it.
  45. Click Open
  46. Select Copy Items if needed
  47. The framework should be added to your project.
  48. In the ViewController.swift file import your Framework: import CustomStack
  49. Replace CustomStack with your frameworks name.
  50. Try to write the code which uses the elements you have packaged within the framework.

Creating Mixed Frameworks (Swift & Objective-C)

The process of creating a mixed library is straightforward. Its almost the same as above with some minor differences.

  1. Follow the steps mentioned above to add your Swift Code.
  2. Add your objective-C files to the project.
  3. While adding the files make sure that the checkbox for the targets is selected appropriately. Screen Shot 2016-08-05 at 1.20.37 PM
  4. Write the code that you wish to write in Objective-C. Of course, if you are including prewritten files then you do not need to do this.
  5. To make the Objective-C code accessible in Swift you need to make the following changes:
    1. In the umbrella header of your framework add the line to import the header
      #import "<FrameworkName>/<HeaderName>.h
    2. Modify the access property located within the target membership of the Objective-C header file. IMG_3527
  6. This should make your Objective-C code accessible to the Swift files.
  7. Test the changes by accessing your Objective-C code in your Swift files within the framework.
  8. Test the changes further by embedding your mixed language framework into a project & then try to access both the Swift as well as Objective-C versions of the code in your new project.
  9. To make your Swift code accessible to Objective-C File make the following changes:
    1. Make sure that your Swift code is compatible with Objective-C. There are 2 ways of doing this. One you can make your Swift class inherit from NSObject. The second way is to use the @objc keyword before your class declaration.
    2. In the Objective-C header file add the line to add the bridging header which is auto generated. You do not need to create your own bridging header.
      #import "<FrameworkName>/<FrameworkName>-Swift.h"

      Replace the word FrameworkName with the name of your Framework.

    3. This should allow you to access your Swift code in your Objective-C header file within the same Framework Project.
  10. This way you can make a single framework which contains code written in both Swift & Objective-C.