• Skip to main content
  • Skip to primary sidebar

Ravi Shankar

Tweaking Apps

  • Swift
  • Tech Tips

Swift

Attribute Unavailable: Estimated section warning before iOS 11.0

November 12, 2021 By Ravi Shankar

Xcode 13 (iOS 15) displays the following warning message for project having minimum deployment as iOS 10.

  • Attribute Unavailable: Estimated section header height before iOS 11.0
  • Attribute Unavailable: Estimated section footer height before iOS 11.0

This warning gets displayed for new UITableViewController added to the Storyboard file. You can get rid of the warning messages by adding 0 to Estimate Header and Estimate footer for Sections under Size Inspector

Filed Under: ios, Swift, Xcode Tagged With: iOS, Xcode Warning

Checklist needed when an issue is reported in your mobile app.

June 22, 2021 By Ravi Shankar

The major work when a bug is reported in your production app is to identify the steps required to replicate the issue.

  1. Get the app version of the device.
  2. Get the operating system version, device model, user locale. Incase of iOS the number of parameters or less where as in case Android it is more.
  3. If it is visual or display error then try to get a screenshot.
  4. If it is a crash then check Firebase Crashlytics or other crash recording framework that you are using.
  5. Check if the crash or issue happening in previous version of the build. This way you can isolate if it is problem related with the latest build.

if you would like add any other steps, please use the comments section. Thank you.

Filed Under: Swift, Tips Tagged With: Issue

Xcode – framework not found FIRAnalyticsConnector

June 22, 2021 By Ravi Shankar

Tried updating all pods in Xcode projects using pod update. Noticed the following messages in the log.

Removing FirebaseInstanceID
Generating Pods project
Integrating client project

After doing Xcode build, noticed the following error.

Framework not found FIRAnalyticsConnector

Looks like firebase pod has been updated and to remove the above error, navigate to Build Settings and search for “FIRAnalyticsConnector”

Open the “Other Linker Flags” setting and remove FIRAnalyticsConnector

Next received “Framework not found FirebaseInstanceID” as well. Repeat the above steps and remove FirebaseInstanceID from Other Linker flags settings. Also make sure to remove from Framework Search Paths (Debug & Release) as well.

Filed Under: Swift, Xcode

We have blocked all requests from this device – Firebase Phone Authentication

September 15, 2020 By Ravi Shankar

Firebase enables apps with Phone Authentication feature but when testing your app you might have received the following error.

We have blocked all requests from this device due to unusual activity. Try again later.

This user usually occurs when you have received too many OTP’s within a short period of time.  And we have to wait for an hour to start using the Phone Authentication feature again.

Recently Firebase has added a feature to add test numbers. This can be found under Firebase Console -> Authentication -> Sign-in method -> Phone

PhoneAuthentication

Now you can use “Phone numbers for testing” section to add test phone numbers. The test numbers will not be blocked and will not affect your testing. I believe you can also use the test numbers for Apple Approval process when publishing your app.

Filed Under: Firebase, ios, Swift Tagged With: Authentication, Firebase

PDFKit – View, Annotate PDF file in Swift

April 10, 2020 By Ravi Shankar 1 Comment

In this demo, we will be using PDFKit to View and Annotate PDF file. Let us start by selecting a Single View App template and name the project as PDFDemo.

For this demo, we will be using a PDF file “TheWakingLights.pdf” and this can downloaded from the github project folder. Now drag and drop this file to Xcode project and in “Choose options for adding these files” select “Copy items if needed”

Displaying PDF

In Xcode’s project navigator, select ViewController.swift and add the following lines after viewDidLoad function.

  
            func openPDFDocument() {   
                guard let path = Bundle.main.url(forResource: "TheWakingLights",                        withExtension: "pdf")
                else { 
                 return     
                }      
                let document = PDFDocument(url: path)   
                let pdfView = PDFView(frame: view.frame)     
                pdfView.document = document       
                view.addSubview(pdfView)  

This function does the following

   guard let path = Bundle.main.url(forResource: "TheWakingLights",
                                         withExtension: "pdf") else { return }

Creates URL instance with the path of “TheWalkingLights.pdf” file.

Loads the pdf file in a PDFDocument object

 let document = PDFDocument(url: path)

Creates an instance of PDFView and sets the frame to ViewController’s view then assigns the PDFDocument to PDFView instance.

        let pdfView = PDFView(frame: view.frame)
        pdfView.document = document
        view.addSubview(pdfView)

You will be seeing couple of unresolved identified errors because of missing import PDFKit statement. Add import statement after import UIKit and now you should be able to run the app on the simulator and select text on the PDF

select text

Adding Annotation to PDF

PDFKit provides option to add annotation to PDF file using PDFAnnoation class. Various annotation can be added like Circle, line, Strikeout, Square, Underline, Highlight etc.. Let us see a code example of adding highlight to PDF page.

Add the following code snippet after openPDFDocument function.

  func highlightAnnotation() -> PDFAnnotation {
        let annotation = PDFAnnotation(bounds: CGRect(x: 30, y: 80, width: 230, height: 50),
                                       forType: .highlight, withProperties: nil)
        annotation.color = .yellow
        return annotation
    }

The above code does the following

  1. Creates a PDFAnnotation instance by specifying coordinates for adding the annotation and setting the type of annotation to highlight.
  2.  Then the annotation colour is set to yellow.

In the openDocument function add the following line after view.addSubView(pdfview)

   pdfView.currentPage?.addAnnotation(highlightAnnotation())

This gets the current page from PDFView and sets the highlight annotation. When you run the app on the simulation you will see the highlight as shown below.

final

Download the source code from here

 

Filed Under: ios, Swift Tagged With: Annotation, PDFDocument, PDFKit, Swift

CoreData tutorial in Swift 5 using NSFetchedResultsController

December 25, 2019 By Ravi Shankar 38 Comments

Let us see an example TaskManager app using CoreData written in Swift Programming language. This app provides the following functionality

  • Allow users to enter new task
  • Update existing task
  • delete task

TaskManager using CoreData201407121030.jpg

You can download source code for this project from Github. If you are familiar with user interface then move on to the Core Data implementation in Swift section

Create a new File -> New -> Project and select template Single View Application

201407121032.jpg

Enter Product Name, Language as Swift and select “Use Core Data” for the new Project.

201407121037.jpg

User Interface Implementation

 

Add new TableViewController for managing tasks

 

Delete ViewController.swift and Add new view controller which will be used for displaying the list of tasks.

201407121059.jpg

Right click on the Project and select New File

201407121101.jpg

Choose the template as Cocoa Touch under iOS -> Source

201407121103.jpg

Enter name of the file as TaskManagerViewController with Subclass as UITableViewController and Language as Swift.

201407121104.jpg

Add new UITableViewController to the Storyboard

 

Navigate to Main.storyboard, delete the ViewController and add new TableViewController to the Storyboard

201407121108.jpg

Embed this TableViewController inside a navigation controller. You can do this by clicking Editor menu -> Embed In -> Navigation Controller.

201407121110.jpg

Navigate to Storyboard file and select Table View Controller. Click Identity Inspector and set the Class to the TaskManagerViewController.

Add button to the navigation bar

 

Users can navigate to new task screen by tapping the button on the TaskManager. Drag and drop the button bar item to the navigation bar.

201407121116.jpg

In the attributes inspector, set the identifier for button bar item as Add. Also enter title as “Task Manager” in the navigation bar.

Add View Controller for entering task detail

 

Now to enter task detail, let us add new View Controller. From the Objects library, drag and drop View Controller on to storyboard. Then drag and drop a navigation item to this View Controller. Add a Done bar button item for saving the changes, Cancel bar button item for dismissing the screen. Also provide a title for the screen as Task Detail.

201407121138.jpg

Then add a textfield to the View Controller to enter details about the task.

201407121540.jpg

Now to connect the Task Manager screen to Task Detail screen, select the Add button in Task Manager screen, hold the control button and make a connection to the Task Detail screen. Select type of Action Segue as Show.

201407121125.jpg201407121127.jpg

Select each View Controller and Click on the Resolve Auto Layout Issues option and pick Reset to Suggested Constraints. This would ensure that the controls alignment and display remains same in different screen sizes.

 

201407121557.jpg

Add View Controller Class

Right click on the Project, select New File from menu list.

201407130919.jpg

Select Cocoa Touch Class as template.

201407130920.jpg

Enter the Class name as TaskDetailViewController, Subclass of UIViewController and Language as Swift.

201407130921.jpg

Navigate to Storyboard file and select Task Detail View Controller. Click Identity Inspector and set the Class to the TaskDetailViiewController.

201407141329.jpg

Now let us add the function required for dismissing the View Controller. This gets called when user taps done and cancel buttons. Navigate to TaskDetailViewController.swift file and add the following functions.

    
   @IBAction func done(sender: AnyObject) {
        if task != nil {
            editTask()
        } else {
            createTask()
        }
        dismissViewController()
    }
    
    @IBAction func cancel(sender: AnyObject) {
         dismissViewController()
    }
    
    // MARK:- Dismiss ViewControllers
    
    func dismissViewController() {
        navigationController?.popViewController(animated: true)
    }

 

Connect the IBActions with the corresponding done and cancel buttons

201407130930.jpg

 

Try to compile and run the app on the Simulator. You should see the following Task Manager screen and tapping + sign should display the Task Detail screen with TextField, Cancel and Done button.

201407130933.jpg201407130935.jpg

 

When you tap the Cancel or Done button should take you to the Task Manager screen.

Create IBOutlet element for UITextField Element

Add the following piece of code after the Class TaskDetailViewController: UIViewController

@IBOutlet var txtDesc: UITextField!

Now use the connection inspector to connect the IBOutlet variable to the textfield on the User Interface.

Core Data Implementation

 

Click Show Project Navigator and select CoreData model file (ending with extension .xcdatamodelid)

201407121042.jpg

Click Add Entity option available at the bottom of Xcode Editor window.

201407121045.jpg

Then enter the name of the entity as Tasks.

201407121047.jpg

Click Add Attribute then enter name as desc and choose the type as String. This attribute will be used for storing the task detail information.

201407121049.jpg

Now to generate the CoreData mapping class, click Editor and select Create NSManagedObject Subclass.

201407121051.jpg

Select the data models and click Next

201407121052.jpg

Then select entities and in this example it is Tasks

201407121053.jpg

Make sure to select Language for NSManagedObject class as Swift. Click Create to the create new class.

201407121055.jpg

Click Yes to to configure an Objective-C birding header for the Swift class.

201407121056.jpg

This should create a new class called Tasks.swfit with variable for corresponding attribute defined in Entities

Write code to save new task details

Add the following line at the top of TaskDetailViewController class

  let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext

The above line defines a variable to store the ManagedObjectContext. In order to save the task information entered in the UITextField, add the following code to TaskDetailViewController.swift. Then call this function in the @IBAction done.

   func createTask() {
        let entityDescripition = NSEntityDescription.entity(forEntityName: "Tasks", in: managedObjectContext)
        let task = Tasks(entity: entityDescripition!, insertInto: managedObjectContext)
        task.desc = txtDesc.text!
        do {
            try managedObjectContext.save()
        } catch _ {
        }
    }
@IBAction func done(sender: AnyObject) {
	createTask()
	dismissViewController()
}

 

The createTask function uses the Tasks Entity class and ManagedObjectContext class to save the information entered in the text field in to SQLite using CoreData.

Now if you try to run this app in Xcode simulator, you should be able to enter the details in textfield and save the task. But there is no way to see the saved tasks.

Write code to retrieve information from SQLite using NSFetchedResultsController

We will be using NSFetchedResultsController to retrieve and manage information returned from Core Data. Write the following code after the class declaration of TaskManagerViewController class

 let managedObjectContext = (UIApplication.shared.delegate as! AppDelegate).managedObjectContext
    
var fetchedResultController: NSFetchedResultsController = NSFetchedResultsController<NSFetchRequestResult>()
    

201407141923.jpg

 

You might see the above error message “Use of undeclared type ’NSFetchedResultsContoller”. This can be fixed by importing CoreData module and making your class a delegate of NSFetchedResultsControllerDelegate.

import CoreData

class TaskManagerViewController: UITableViewController, NSFetchedResultsControllerDelegate {

Then add the following function to populate fetchedResultController.

  
    func getFetchedResultController() -> NSFetchedResultsController<NSFetchRequestResult> {
        fetchedResultController = NSFetchedResultsController(fetchRequest: taskFetchRequest(),  managedObjectContext: managedObjectContext, sectionNameKeyPath: nil, cacheName: nil)
        return fetchedResultController
    }
      

 

Update the ViewDidLoad method of TableViewController to populate fetchedResultController variable and set the delegate to self and call the function to retrieve the results.

override func viewDidLoad() {
        super.viewDidLoad()

       fetchedResultController = getFetchedResultController()
        fetchedResultController.delegate = self
        do {
            try fetchedResultController.performFetch()
        } catch _ {
        }
    }

Implement the TableView related functions to display the data

Navigate to Main.storyoard then to TaskManagerViewController and set Identifier for Prototype Cells as “Cell”

201407142004.jpg

 

Add the following functions required for population of rows in tableView and to refresh the tableView when content is changed.

 

And for refreshing the tableview content add the following piece of code snippet.

  func controllerDidChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {          tableView.reloadData()
    }

Swift uses namespaces for classes, so the downcast of NSManagedObject class to Tasks class will work only when you append the module name with the class for Entity

  let task = fetchedResultController.object(at: indexPath as IndexPath) as! Tasks

Navigate to TaskManager.xcdatamodeld, select Tasks under Entities and using the Data Model Inspector append Module name i.e TaskManager with the class.

201407142038.jpg

 

 

Now you should be able to see the data added via TaskDetailScreen in the TaskManager Screen.

201407142059.jpg

Implementation of deleting rows from tableView and CoreData entity

 

Copy and paste the following code to provide the users with the option to delete the rows.

 override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        let managedObject:NSManagedObject = fetchedResultController.object(at: indexPath as IndexPath) as! NSManagedObject
        managedObjectContext.delete(managedObject)
        do {
            try managedObjectContext.save()
        } catch _ {
        }
    }

201407142116.jpg

Implementation of editing task details

Now let us see how to edit a task in the TaskManager screen. We will re-use the same TaskDetail screen for editing the task information. First let create segue from UITableViewCell to TaskDetailViewController. You can do this by holding the Control key and drag and drop the connection to TaskDetailViewController.

201407142127.jpg

 

Make sure to set the Segue identifier as edit using Attributes Inspector

201407142128.jpg

 

Add the following piece of code in TaskManagerViewController to populate the task detail for the edited row.

      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "edit" {
            let cell = sender as! UITableViewCell
            let indexPath = tableView.indexPath(for: cell)
            let taskController:TaskDetailViewController = segue.destination as! TaskDetailViewController
            let task:Tasks = fetchedResultController.object(at: indexPath!) as! Tasks
            taskController.task = task
        }
    }
    

 

Navigate to TaskDetailViewController and variable which used to pass the task details across the ViewControllers

var task: Task? = nil

In viewDidLoad fund, populate the textField with the task details for edit operation i.e task is not nil

 override func viewDidLoad() {
        super.viewDidLoad()
     if task != nil {
            txtDesc.text = task?.desc
        }
    }

 

Then add a new function to save the edited task. Also modify the done function to handle create and edit task functionality

func editTask() {
       task?.desc = txtDesc.text!
        do {
            try managedObjectContext.save()
        } catch _ {
        }
    }
@IBAction func done(sender: AnyObject) {
        if task != nil {
            editTask()
        } else {
            createTask()
        }
        dismissViewController()
    }

 

Now when you run the app in Xcode simulator, you should be able to edit the task.

The final piece of code left is to add background colour to the navigation bar for both the controllers. Click AppDelegate.swift file and add the following function. Then call this function from the didFinishLaunchingWithOptions.

    func setupAppearance() {
        let navigationBarAppearance = UINavigationBar.appearance()
        navigationBarAppearance.barTintColor = UIColor(red: 51.0/255.0, green: 104.0/255.0, blue: 121.0/255.0, alpha: 1.0)
        navigationBarAppearance.tintColor = UIColor.white
        navigationBarAppearance.titleTextAttributes = [NSAttributedString.Key.foregroundColor:UIColor.white]
    }

 

Running the app on the iOS simulator should change the appearance for the navigation bar.

201407142233.jpg

 

Hope you found this beginner tutorial useful. Please use the comments section to share your thoughts and suggestion

Download the source code for this tutorial from GitHub

Filed Under: Develop, ios, iPhone, Programming, Swift, Xcode Tagged With: CoreData, delegation, NSFetchedResultContoller, Swift, Tutorials, UITableView, User Interface, Xcode

Journey with Swift

October 29, 2017 By Ravi Shankar

This is about my journey as a Swift developer and some of the points discussed here could be useful to anyone who want to re-invent themselves as a software developer or if they want start a career as a Software developer.

Past experience

I have been working in Software industry for years in wide range of technologies. Like many I felt the need for a change and wanted to switch over to the latest technologies. I was interested in iOS app development though I started with Objective-C within a year switched to Swift.

Be an early adopter

Choosing the technology matters and if you are one of the early adopter then you get new opportunities quickly. Being one of the early adapter of Swift helped me a lot to get noticed quickly. Also if the technology has the backing of some big corporates then you will grow with the technology.

Blog a learning tool

I started writing simple tutorials in Swift and shared this with the wider audience through my blog. This helped me to articulate the concepts well and also get valuable feedback from readers. In the later stage I got many opportunities/leads through my blog. Check out Ash Furrow and Kristina Thai talks on the benefiting of writing a blog.

Stay focussed

After picking up iOS/Swift, I got distracted time and again with Android and other hybrid platforms. But remember the process of learning any technology is the same and you are not going to achieve your goal by focussing on different platforms at the same time. Stay focussed to reach your goal quickly.

Build a portfolio

Another way of building confidence is to publish apps under your name. You can start with simple apps and increase the features as you gain more and more experience. I sometimes felt embarrased with the choice of initial apps that I made and the code that I wrote. It is quite natural to feel that way as long you keep learning continuously

Eat Swift, Sleep Swift, Breathe Swift

Don’t put all your eggs in one basket. I was working as a Objective-C developer but quit the job to focus only on Swift. There were not many gigs available during the first year hence become an iOS mentor. The best way to keep learning is by teaching others. This allowed me to spend all my time in learning and practising Swift.

Networking and team events

Join local meet-ups learn from other like minded people. If possible attend conferences where you get a chance to meet some international speakers as well. Participate in Hackathons and test your ability in new technologies by conceptualising the app idea in to MVP in the short period of time.

Take up new opportunities

I got a lead through my blog for reviewing a Swift book and also to co-author a Udemy course. Don’t hesitate to take up new opportunities as long as it aligns with your technology. This can alway add up to your portfolio and online presence.

Hard work, dedication!

After many unsuccessful bidding finally I got a small prototype work in Swift. The client again awarded me a full fledged project which later become a full-time work. Even if it is a small gig, hard work and dedication definitely pays off.

 

I want to end with one quote this is especially for the people in their 30s & 40s. You can become or re-invent yourself as software developer at any age. “Age is no barrier. It’s a limitation you put on your mind”. Don’t compare yourself with other developers know your strength and work around your limitations. Happy Coding!!

Filed Under: ios, iOS Developer, Software Developer, Swift

My first iOS developer conference – try! Swift Tokyo 2017

October 28, 2017 By Ravi Shankar 2 Comments

Attending conference is one way of keeping yourself up to date with the latest trends in any industry. This is true for every software developer as well. After re-skilling myself and picking up iOS development I wanted to attend some good conferences but not many were happening in India. Heard a lot about try! Swift from Alvin and Giridharan and registered for try! Swift Tokyo.

Conference

I needed a visa to travel to Japan and the organisers were quick to help me out. Thanks to Katsumi and Natasha for the paper work, the level of commitment shown to sort this out gave me a glimpse of what to expect in the conference.

I had arrived a day earlier and was able to attend the Tokyo Skytree tour followed by a reception at Pivotal labs arranged for all the international attendees. This was like an ice breaker and I got introduced to few of the attendees and speakers as well.

The conference was for 2 days + 1 day for workshops and hackathon. Each session was scheduled for 25 minutes followed by office hours with the speaker where you get a chance to clarify your queries and have detailed discussion with some renowned speakers. They had also scheduled lighning talks with duration of 5 minutes each. This was a huge conference with 700+ attendess, great speakers and well organised one as well.

Hackathon and Workshop

After the 2 day conference all the attendees had a chance to participate in hackathon. This gave me a chance to work with some bright Japanese developers. There were also some workshops conducted by Realm, IBM, Build a cross-platform 2D game with Swift by @ewingfighter and React Native workshop by orta

Why should anyone attend?

  • Networking with attendees and speakers, use the office hours after talk to clarify the queries with the speakers.
  • You can participate in the social events after conference. trySwift are the best at this.
  • If you are interested in job opportunities then you have chance to meet companies as many sponsors were doing recruitment as well
  • Get up to speed in new iOS technologies and chance to know about some exciting startups.
  • You can also participate in the local Swift and iOS community events.
  • On a side note you have a chance to explore country and interact with people.

It was worth the money spent and would recommend this for all iOS developer especailly try! Swift conferences.

Now try! Swift has come to India as well !! Register Now

Filed Under: Conference, ios, Networking, Swift, try! Swift

  1. Pages:
  2. 1
  3. 2
  4. 3
  5. »
Next Page »

Primary Sidebar

TwitterLinkedin

Recent Posts

  • How to block keywords in Jio broadband
  • How to disable opening an app automatically at login in Mac
  • How to set preferred Wifi network on Mac
  • Attribute Unavailable: Estimated section warning before iOS 11.0
  • How to recover Firefox password from Time Machine backup

Pages

  • About
  • Privacy Policy
  • Terms and Conditions

Copyright 2022 © rshankar.com

Terms and Conditions - Privacy Policy