Showing posts with label swift3. Show all posts
Showing posts with label swift3. Show all posts

Friday, September 14, 2018

fileprivate to private


In Swift 3, If we need to access private stuff of a class in extension, we need to change the access specifier from private to fileprivate.


     
  class User {
    
    private var name: String
    private var id: Int
    
    init(name: String, id: Int) {
        self.name = name
        self.id = id
    }
    
    private var greeting: String {
        get {
            return "Hi \(name)"
        }
        set(v) {
            name = v
        }
    }
    
 }

 extension User {
    func greetUser() {
        print(greeting)
    }
 } 



Swift 3 gives build error for below as greeting is private. 



     
  extension User {
    func greetUser() {
        print(greeting)
    }
  }



It should be marked as fileprivate which makes it accessible to others which are inside a file which may not be we wanted most of the times.

Swift 4, makes it appropriate based on their name.

private is not at all accessible outside even with in the same file.

fileprivate is accessible only with in the file, Not accessible outside of a file.

If greeting is with in the same file where User class is there, It doesn’t matter If it’s fileprivate or private to access it in a User extension with in the same file. But, careful with fileprivate cause it is accessible with in the same file. 


     
  class User {
    
    private var name: String
    private var id: Int
    
    init(name: String, id: Int) {
        self.name = name
        self.id = id
    }
    
    fileprivate var greeting: String {
        get {
            return "Hi \(name)"
        }
        set(v) {
            name = v
        }
    }
    
 }

 extension User {
    func greetUser() {
        print(greeting)
    }
 }



If you are writing extension of User in another file, You can not access it If it’s fileprivate or private.

Extension outside of file,


     
  extension User {
    func greetUser() {
        print(greeting)
    }
  }



fileprivate build error - 'greeting' is inaccessible due to 'fileprivate' protection level

private build error - 'greeting' is inaccessible due to 'private' protection level


That’s how Swift 4, make both the access specifiers clear based on their name. 

Glad, It’s not confusing now like in Swift 3.

Swift 3, fileprivate -  If you need access throughout the file even in extensions (private gives build error in extensions)

Swift 3, private - Not accessible outside the model scope even in the extension which is there in same file.

Swift 4, fileprivate - If you need access throughout the file.

Swift 4, private - Accessible in extensions If they are in the same file. Not accessible for all remaining cases.

Take Aways - 

In Swift 4, We don’t need to change fileprivate access for a property/method to private to access that in the extension in the same file.


Hope this post is useful. Feel free to comment incase of any queries.


Sunday, October 8, 2017

Swift 4 NEW Tutorial-2 (Strings are Collections Again)

Prior to Swift 3, Strings are collection types, Now again in Swift 4 they are collections.

Swift 3 

-------------------------------------------------------------------------

var str = “Hello World!”
str.characters.count
str.characters.append(“appending….”)

-------------------------------------------------------------------------

Swift 4 

-------------------------------------------------------------------------

var str = “iOS Solves”
str.count        // 10
str.append(“ Blog”)      // iOS Solves Blog

-------------------------------------------------------------------------

Multiline strings :-

Swift 3

let name = “name1 \n name2 \n name3”

Output:

name1
name2
name3

Swift 4

Use 3 double quotes to specify it as a multiline string.

-------------------------------------------------------------------------

let name = “””
name1
name2
name3
“””

Output:

name1
name2
name3

-------------------------------------------------------------------------

Use spaces for indentation

-------------------------------------------------------------------------

let name = “””
  name1
  name2
  name3
“””

Output:

  name1
  name2
  name3

-------------------------------------------------------------------------

Hope this post is useful. Feel free to comment incase of any queries.


Monday, July 24, 2017

Swift 3 - CoreData - Validations (Tutorial-2)

In Tutorial-1, We have seen the basic CRUD operations with CoreData.
In this tutorial, Let’s see some data validations.

Please checkout the code from here

Let’s suppose we need a 10 character validation on name attribute in Person model. We can set these validations in the HitList.xcdatamodeld it self as shown below.









After we set these min and max limit validations, If we try to save a name of more than 10 characters, CoreData reports the error like shown below.



  CoreDataManager.sharedInstance.savePerson(id: self.people.count + 1, name: 
              nameToSave, lastUpdated: Date(), 
              grade: personGrade, onCompletion: { (person: NSManagedObject) in
                self.people.append(person)
                self.tableView.reloadData()
            }, onFailure: { (err: NSError) in
                print("Insert Error :- \(err)")
            })



   Insert Error :- Error Domain=NSCocoaErrorDomain Code=1660 
   "The operation couldn’t be completed. (Cocoa error  1660.)" UserInfo=    
   {NSValidationErrorObject=
  (entity: Person; id: 0x60800002d380
   ///Person/t2DCF2680-674D-4CBA-B50B-A741BE0667482> ; data: {
    active = 1;
    id = 1;
    lastUpdated = "2017-07-24 10:07:12 +0000";
    name = "sfdfgdsgdfghgj ghjghj";
  }), NSValidationErrorValue=sfdfgdsgdfghgj ghjghj, NSValidationErrorKey=name, 
  NSLocalizedDescription=The operation couldn’t be completed. (Cocoa error 1660.)}




From this error, We can know like there is some validation missing in name attribute. But this error is not clearly giving info like whether it’s a min validation or max validation until unless we check name string length.

The interesting part here is, NSManagedObject has methods which will get called upon CRUD.



  open func validateValue(_ value: AutoreleasingUnsafeMutablePointer
                                                                forKey key: String) throws // KVC

  open func validateForDelete() throws

  open func validateForInsert() throws

  open func validateForUpdate() throws



We can override these methods in our NSManagedObject object sub classes and can write our own validation logics.

Please check Person subclass of NSManagedObject for these validations.



      public override func validateForInsert() throws {
        if let personName = self.name {
            if personName.isEmpty {
                throw NSError(domain: Person.PersonNameErrorDomain, code: 
                    Person.errorCodes.minLimitNotReached.rawValue, userInfo: ["message" : 
                    Person.PersonNameMinLimit])
            }
            else if personName.characters.count > 10 {
                throw NSError(domain: Person.PersonNameErrorDomain, code:    
                    Person.errorCodes.maxLimitExceeded.rawValue, userInfo: ["message" : 
                    Person.PersonNameMaxLimit])
            }
        }
        
        if !self.isValidGrade() {
            throw NSError(domain: Person.PersonGradeErrorDomain, code: 100, userInfo: 
                                                 ["message" : "Grade should be one of [A, SA, M]"])
        }
    }
    
    public override func validateForUpdate() throws {
        if let personName = self.name {
            if personName.isEmpty {
                throw NSError(domain: Person.PersonNameErrorDomain, code: 
                      Person.errorCodes.minLimitNotReached.rawValue, 
                          userInfo: ["message" : Person.PersonNameMinLimit])                      
            }
            else if personName.characters.count > 10 {
                throw NSError(domain: Person.PersonNameErrorDomain, code: 
                      Person.errorCodes.maxLimitExceeded.rawValue, userInfo: ["message" : 
                      Person.PersonNameMaxLimit])
            }
        }
    }




Hope this post is useful. Feel free to comment incase of any queries.


Tuesday, June 13, 2017

Objective-C/Swift 3 avoid crashes in iPad in an iPhone Application

Targeting iOS app only for iPhone devices and run it on iPad devices, App gets crashed for UIAlertController(actionSheet) and UIAlertController.

Ever faced?

Let’s see the reason for crash and the fix for it.

(I am going to use Swift 3.0 in this post)


UIAlertController(actionSheet)




        let optionsMenu = UIAlertController(title: nil, message: "", 
                                                                     preferredStyle: .actionSheet)

        let deleteAction = UIAlertAction(title: “Delete”), style: .destructive, 
                                                                                                  handler: {
            (alert: UIAlertAction!) -> Void in
            //Delete Action
        })

        let saveAction = UIAlertAction(title: “Edit”, style: .default, handler: {
            (alert: UIAlertAction!) -> Void in
             // Edit Action
        })

        let cancelAction = UIAlertAction(title: “Cancel”, style: .cancel, handler: {
            (alert: UIAlertAction!) -> Void in
             //Cancel Action
        })

        optionsMenu.addAction(saveAction)
        optionsMenu.addAction(deleteAction)
        optionsMenu.addAction(cancelAction)

       self.present(optionMenu, animated: true, completion: nil)



 The above code works fine on iPhone device, But crashes on iPad device.

 The reason is in iPad, The presentation is going to be like a popover. 

 So we need to give either sourceView or barButtonItem as a source to the 
 popover as shown below.




   if (UIDevice.current.userInterfaceIdiom == .pad) {

       if let presentation = optionMenu.popoverPresentationController {

          presentation.barButtonItem = ((self.navigationItem.rightBarButtonItems)!)[0]

       }

  }




UIActivityViewController


  let sharingItems = [“share me….”] as [Any]

  let activityViewController = UIActivityViewController(activityItems: sharingItems, 
                                                                                     applicationActivities: nil)

   activityViewController.completionWithItemsHandler = 
                                                               {activity, completed, items, error in    
        }             
  
   self.present(activityViewController, animated: true, completion: nil)

    Same thing happens with UIActivityViewController. It crashes in iPad.
    Here also we need to provide sourceView/barButtonItem for iPad.

    if let popOverVC = activityViewController.popoverPresentationController { 

         if let navItems = self.navigationItem.rightBarButtonItems {
                popOverVC.barButtonItem = navItems[0]
         }

         else {
             popOverVC.sourceView = self.view
        }


    }



Hope this post is useful. Feel free to comment incase of any queries.



Friday, February 24, 2017

Swift 3 Getting Age from DOB

If we have a functionality like user enters his/her DOB date and we need to calculate age or we are getting DOB string from service response and we need to calculate user’s age, Welcome to this post and see how to calculate age based on DOB.

In this post I am going to explain how to calculate age If we have a DOB string in
yyyy-MM-dd format.


  
 extension Date {
    var age: Int {
        return Calendar.current.dateComponents([.year], from: self, to: Date()).year!
    }
 }

 let strDOB = "1986-06-28" 

 let ageComponents = strDOB.components(separatedBy: "-") //["1986", "06", "28"]

 let dateDOB = Calendar.current.date(from: DateComponents(year:  
                                    Int(ageComponents[0]), month: Int(ageComponents[1]), day: 
                                    Int(ageComponents[2])))!   
                                                                 //Jun 28, 1986, 12:00 AM

 let myAge = dateDOB.age  //30


I have taken a simple Date extension where I am having age property which gives me number of years from current year technically. from is DOB date and to is current date.

My DOB string(1986-06-28), I am splitting by separator '-' and getting year, month and date strings, converting them to Ints and passing to Calendar's current date from components method to convert it to Date object and calling age property in my extension to get number of years gap from DOB date to current date which is technically user's age.

Hope this post is useful. Feel free to comment incase of any queries.


Tuesday, January 31, 2017

Checking whether a view is a subview of another view

Instead of taking all the subviews of a view into an array and looping through to check whether a view is a subview or not, We can use isDescendant method of UIView class too quickly and simply check that condition.


  
       open func isDescendant(of view: UIView) -> Bool // returns YES for self.


        let parentView:UIView = UIView.init()
        let childView:UIView = UIView.init()
        
        if (childView.isDescendant(of: parentView)) {
        }



It works for child of Childs and parent of parents also.


Hope this post is useful. Feel free to comment incase of any queries.