Skip to main content

Access Control by using Access Specifiers

Access Control by using Access Specifiers

 iOS Developer level : Intermediate

 

Configuration when this article was written

 

Xcode : Version 11.5

MacOS : 10.15.5 (Catalina)

 

A working example

Final code can be found in the Resources section below.  



Access control restricts access to parts (like functions, class, structure, variables …. etc ) of your code from code in other source files and modules.

 

So lets understand what do we mean by Modules and Source Files

 before we head forward

 

Modules and Source Files

 

module is a single unit of code distribution—a framework or application that is built and shipped as a single unit and that can be imported by another module with Swift’s import keyword.

In the example below (which I will coverup shortly) SharedFunctionality is a Module

 

source file is a single Swift source code file within a module (in effect, a single file within an app or framework).

In the example below (which I will coverup shortly) MySimpleClass.swift is a source file

 

Enough of introduction , let’s be technical…

 

Following are the Access Specifiers supported in Swift

 

·       Open access and public access enable entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. You typically use open or public access when specifying the public interface to a framework.

 

Open access applies only to classes and class members, and it differs from public access by allowing code outside the module to subclass and override.

 

·       Internal access (This is the default access level) enables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure.

 

 

·       File-private access restricts the use of an entity to its own defining source file. Use file-private access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.

 

·       Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.

 

 

Open access is the highest (least restrictive) access level and private access is the lowest (most restrictive) access level.

 

A working example

 

Final code can be found in the references section below.  You can also see the output by downloading and running the code. Just uncomment the code (wherever mentioned) to see the impact caused by access levels

 

Start by creating a  Single view app and name it as AccessSpecfiersInAction

 

Xcode -> New Project -> Single View App -> AccessSpecfiersInAction

 

Save.

 

Now add an empty swift file and name it as MySimpleClass

 

Add the following to the file

 

open class MyOpenClass {

    func methodWithDefaultAccessSpecifier() {}

    open func methodWithExplicitAccessSpecifier() {}

}

 

public class MyPublicClass {

    func methodWithDefaultAccessSpecifier() {}

    public func methodWithExplicitAccessSpecifier() {}

}

 

//Internal is the default access

internal class MyInternalClass {

    func methodWithDefaultAccessSpecifier() {}

    internal func methodWithExplicitAccessSpecifier() {}

}

 

 

class MyDefaultClass {

    func methodWithDefaultAccessSpecifier() {}

    func methodWithExplicitAccessSpecifier() {}

}

 

 

fileprivate class MyFilePrivateClass {

    func methodWithDefaultAccessSpecifier() {}

    fileprivate func methodWithExplicitAccessSpecifier() {}

}

 

 

private class MyPrivateClass {

    func methodWithDefaultAccessSpecifier() {}

    private func methodWithExplicitAccessSpecifier() {}

}

 

 

class AccessWithinSameFile {

   

   

    func simpleCheckMethod() -> Void {

       

       

        let openClass = MyOpenClass()

        openClass.methodWithDefaultAccessSpecifier()

        openClass.methodWithExplicitAccessSpecifier()

       

        let publicClass = MyPublicClass()

        publicClass.methodWithDefaultAccessSpecifier()

        publicClass.methodWithExplicitAccessSpecifier()

       

        let internalClass = MyInternalClass()

        internalClass.methodWithDefaultAccessSpecifier()

        internalClass.methodWithExplicitAccessSpecifier()

       

        let defaultClass = MyDefaultClass()

        defaultClass.methodWithDefaultAccessSpecifier()

        defaultClass.methodWithExplicitAccessSpecifier()

       

        let filePrivateClass = MyFilePrivateClass()

        filePrivateClass.methodWithDefaultAccessSpecifier()

        filePrivateClass.methodWithExplicitAccessSpecifier()

       

        let privateClass = MyPrivateClass()

        privateClass.methodWithDefaultAccessSpecifier()

        privateClass.methodWithExplicitAccessSpecifier()

    }

}

 

 

Now build the Xcode project . You will see error as follows

 





'methodWithExplicitAccessSpecifier' is inaccessible due to 'private' protection level

 

This because method methodWithExplicitAccessSpecifier inside MyPrivateClass is marked private and is not accessible outside MyPrivateClass.

 

Now comment this line

 

privateClass.methodWithExplicitAccessSpecifier()

 

and it should look like the following

 

//        let privateClass = MyPrivateClass()
//        privateClass.methodWithDefaultAccessSpecifier()

//        privateClass.methodWithExplicitAccessSpecifier()

 

 

Now run your code, should have no issues now

 

 

Now in ViewController.swift in the viewDidLoad() add the following

 

let openClass = MyOpenClass()

openClass.methodWithDefaultAccessSpecifier()

openClass.methodWithExplicitAccessSpecifier()

 

let publicClass = MyPublicClass()

publicClass.methodWithDefaultAccessSpecifier()

publicClass.methodWithExplicitAccessSpecifier()

 

let internalClass = MyInternalClass()

internalClass.methodWithDefaultAccessSpecifier()

internalClass.methodWithExplicitAccessSpecifier()

 

let defaultClass = MyDefaultClass()

defaultClass.methodWithDefaultAccessSpecifier()

defaultClass.methodWithExplicitAccessSpecifier()

 

let filePrivateClass = MyFilePrivateClass()

 

let privateClass = MyPrivateClass()

 

 Now build the Xcode project . You will see error as follows

 

Use of unresolved identifier

 


This is because we cannot access any class, structure , variables etc which are marked fileprivate outside the source file where it is declared. Here the source file is MySimpleClass.swift and we are accessing in  ViewController.swift.

 

So now we understand how fileprivate and private work.

 

 

To understand internal,public and open access specifier lets create a framework and name it SharedFunctionality

 

Goto


Xcode -> New Project -> Framework under iOS tab-> SharedFunctionality

 

Save it anywhere, in my case I will save it on Desktop

 

 

Add a new swift file and name it SharedFeature.swift to SharedFunctionality project and add the following.

 

 

import Foundation


open class ExternalOpenClass {

    public init() {}


    /*

     We cannot use open access level to init.

     open init() { // error: only classes and overridable class members can be declared 'open'; use 'public'  Refer screenshot below

 

    }*/


    func methodWithDefaultAccessSpecifier() {}

    open func methodWithExplicitAccessSpecifier() {}

}

  

public class ExternalPublicClass {

    public init() {}

    func methodWithDefaultAccessSpecifier() {}

    public func methodWithExplicitAccessSpecifier() {}

}

 


internal class ExternalInternalClass {

    public init() {}

    func methodWithDefaultAccessSpecifier() {}

    internal func methodWithExplicitAccessSpecifier() {}

}

 

class ExternalDefaultClass {

    public init() {}

    func methodWithDefaultAccessSpecifier() {}

    func methodWithExplicitAccessSpecifier() {}

}

 

 

 If you see the code about we have tagged init with public, This is to make it available outside this framework.



 

Now build the project and close the project from xcode

 

 

Open our AccessSpecfiersInAction project  and add SharedFunctionality framework

 

-   Right Click on AccessSpecfiersInAction in project navigator

-   Traverse to folder where you have saved SharedFunctionality

-   Open SharedFunctionality and add SharedFunctionality.xcodeproj

 

 

 

You can also follow as per screen shots below





  

After adding it should like the screenshot below


 

 

Build the project to see no errors.

 

 

Now open ViewController.swift and add the following. Lets comment out the earlier code so we can test access levels from our SharedFunctionality framework.

 
          let openClass = ExternalOpenClass.init()
          //openClass.methodWithDefaultAccessSpecifier()
          openClass.methodWithExplicitAccessSpecifier()
          public func methodMarkedPublic() {}
       
          let publicClass = ExternalPublicClass()
          //publicClass.methodWithDefaultAccessSpecifier()
          publicClass.methodWithExplicitAccessSpecifier()
       
          //let internalClass = ExternalInternalClass()
          // let defaultClass = ExternalDefaultClass()

 

 

Now uncomment

 

let internalClass = ExternalInternalClass()

       

let defaultClass = ExternalDefaultClass()

 

You see that there is an error since ExternalInternalClass and ExternalDefaultClass is internal and we are accessing them outside SharedFunctionality module

 

 

So now we understand how internal access level work.

 

 

To Look at how open and public work

 

Create a new file in called InheritClass.swift in AccessSpecfiersInAction project.

 

Add the following code

 

class CustomOpenClass: ExternalOpenClass {

   

    override func methodWithExplicitAccessSpecifier() {

        print("I am overriden")

    }

   

}

 

Now we see that We can ExternalOpenClass and also override methodWithExplicitAccessSpecifier method, Since we have added open access level.

 

 

Now Modify the code to look as below

 

class CustomOpenClass: ExternalOpenClass {

   

    override func methodWithExplicitAccessSpecifier() {

        print("I am overriden")

    }

   

    override func methodMarkedPublic() {

    }

}

 

 

 

You will see error (Overriding non-open instance method outside of its defining module) when you try to override methodMarkedPublic(). This is because public methods from other module cant be overridden.




 

 

Now add the following code

 

 

class CustomPublicClass: ExternalPublicClass {

   

}

 

You will see error (Cannot inherit from non-open class 'ExternalPublicClass' outside of its defining module) when you try to subclass ExternalPublicClass(). This is because public class from other module cant be subclassed.

 



 

Lets summarise

 


·       Open access and public access enable entities to be used within any source file from their defining module, and also in a source file from another module that imports the defining module. You typically use open or public access when specifying the public interface to a framework.

 

Open access applies only to classes and class members, and it differs from public access by allowing code outside the module to subclass and override.

 

·       Internal access (This is the default access level) enables entities to be used within any source file from their defining module, but not in any source file outside of that module. You typically use internal access when defining an app’s or a framework’s internal structure.

 

 

·       File-private access restricts the use of an entity to its own defining source file. Use file-private access to hide the implementation details of a specific piece of functionality when those details are used within an entire file.

 

·       Private access restricts the use of an entity to the enclosing declaration, and to extensions of that declaration that are in the same file. Use private access to hide the implementation details of a specific piece of functionality when those details are used only within a single declaration.




We stop here ...



Resources:

 

 https://github.com/TeaTalkInternal/AccessSpecifiers


 

My Reference :  

 

https://www.youtube.com/watch?v=S7cs6nURvG0

https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html

 

 

 


Comments

Popular posts from this blog

Helper Sites to build your Mobile App

Helper Sites to build your Mobile App ( Primary Stuff ) Idea to App   Following are the links , supporting your journey in transforming an idea into an app   Wireframes Have the screens you want  your  app to a have drawn on paper. Then have the photos of each screen clicked individually , Then use POP  https://marvelapp.com/pop/   . This  app helps you have your wireframes connected, just like an mock app.   Color Theme To decide on the color for your apps use   https://colorhunt.co/   https://www.materialpalette.com/ Visual Design To refer already existing designs use  https://pttrns.com/  , To design VD use  https://www.uxpin.com/   Free icons  (Free for commercial use) https://www.flaticon.com/ https://icons8.com/ https://www.iconfinder.com/free_icons Background Images   use   http://www.resplashed.com/     App Icons   To create app icons use  https://makeappicon.com/   App Store Screen Shots  https://theapplaunchpad.com   http://sketchtoappstore.com/   App Landing Page   To create

How to create your cocoapods?

Lets write our cocoapod and publish it to cocoapods.org    iOS Developer level :  Intermediate   Configuration when this article was written   Xcode :  Version 11.5 MacOS :  10.15.5 (Catalina)   A working example   Final code can be found in the Resources section below.     What is a cocoapod ?         CocoaPods  is an  application level dependency manager  for the  Objective-C ,  Swift  and any other languages that run on the Objective-C runtime, such as  RubyMotion , that provides a standard format for managing external  libraries.            CocoaPods focuses on source-based distribution of third party code and automatic integration into Xcode projects. Enough of introduction , let’s be technical… So to start let us create a framework using xcode.   Xcode -> New -> Project -> Framework   Name It as TTDeviceIdentifier   Inside create a file called DeviceIdentifier   Add following code   import  UIKit   public   struct  DeviceIdentifier {          public   static   func  get