0

i'm very new to Swift.I have following code which works perfectly. i.e. I'm fetching contacts from PhoneBook and updating into sqlite successfully.

My requirement

I want to run code in background i.e. in my following code what i'm doing is whenever some contacts added/deleted in Phonebook I'm updating sqlite. This feature continuously i want. It should always run in background.

Here is my code

func getContactNames()
{
    if !self.determineStatus()
    {
        print("not authorized")
        return
    }

    let contactList: NSArray = ABAddressBookCopyArrayOfAllPeople(adbk).takeRetainedValue()
    print("records in the array \(contactList.count)")


    var firstName : String = String()

    var contactNumber : String = String()


    var lastName : String = String()


    var email : String = String()


    var fullName : String = String()


    let db = ContactsDBModel.sharedInstance()


    var  contacts : [ContactsModel!]?


    contacts =  db.selectAllFromContact()

    print(contacts?.count)

    if contacts?.count != contactList.count
    {

        db.deleteAllFromContact()

        for record:ABRecordRef in contactList
        {
            if (ABRecordCopyValue(record,
                kABPersonPhoneProperty) != nil)

            {


                if (ABRecordCopyValue(record,
                    kABPersonFirstNameProperty) != nil)

                {


                    firstName = (ABRecordCopyValue(record, kABPersonFirstNameProperty)?.takeRetainedValue() as? String)!

                    let numbers:ABMultiValue = ABRecordCopyValue(record, kABPersonPhoneProperty).takeRetainedValue()


                    contactNumber = (ABMultiValueCopyValueAtIndex(numbers,0)?.takeRetainedValue() as? String)!
                    // print("first name =\(firstName)")

                   // print("contact number=\(contactNumber)")

                    if (ABRecordCopyValue(record,
                        kABPersonLastNameProperty) != nil)
                    {

                       lastName = (ABRecordCopyValue(record,
                            kABPersonLastNameProperty).takeRetainedValue()as? String)!
                       // print("last name =\(lastName)")
                    }


                    let emails: ABMultiValueRef = ABRecordCopyValue(record, kABPersonEmailProperty).takeRetainedValue()

                    for (var i = 0; i < ABMultiValueGetCount(emails); i++)
                    {
                        email = ABMultiValueCopyValueAtIndex(emails, i).takeRetainedValue() as! String
                      //  print("email of person=\(email)")
                    }

                }

            }

            fullName = firstName + lastName;
            lastName = "";

            print("fullName of person=\(fullName)")
            print("email of person=\(email)")
            print("contact number=\(contactNumber)")


            db.insertIntoContact(contactNumber: contactNumber, contactName: fullName, contactEmail: email)


        }

        contacts =  db.selectAllFromContact()

        print(contacts?.count)

  }


    print(contacts?.count)


} 

The above code i want to run in background.

UPDATE

viewDidLoad

override func viewDidLoad()
{
    super.viewDidLoad()
    var emptyDictionary: CFDictionaryRef?
    var addressBook: ABAddressBookRef?

            func extractABAddressBookRef(abRef: Unmanaged<ABAddressBookRef>!) -> ABAddressBookRef?
            {
                if let ab = abRef
                {
                    return Unmanaged<NSObject>.fromOpaque(ab.toOpaque()).takeUnretainedValue()
                }
                return nil
            }

            if (ABAddressBookGetAuthorizationStatus() == ABAuthorizationStatus.NotDetermined)
            {
                print("requesting access...")
                var errorRef: Unmanaged<CFError>? = nil
                addressBook = extractABAddressBookRef(ABAddressBookCreateWithOptions(nil, &errorRef))
                ABAddressBookRequestAccessWithCompletion(addressBook, { success, error in
                    if success {
                        self.getContactNames()
                    }
                    else
                    {
                        print("error")
                    }
                })
            }
            else if (ABAddressBookGetAuthorizationStatus() == ABAuthorizationStatus.Denied || ABAddressBookGetAuthorizationStatus() == ABAuthorizationStatus.Restricted)
            {
            print("access denied")
            }
            else if (ABAddressBookGetAuthorizationStatus() == ABAuthorizationStatus.Authorized)
            {
            print("access granted")
            getContactNames()
            }


   }

dispatch_async

 dispatch_async(dispatch_get_global_queue(   DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
//Background Thread
 dispatch_async(dispatch_get_main_queue(), ^(void){
    //Run UI Updates
    });
 });

I've heard using dispatch_async we can run code in background.But where to put my above code? what are the scenarios?

Shrikant K
  • 1,988
  • 2
  • 23
  • 34
  • 2
    "This feature continuously i want. It should always run in background", you can't run something infinitely in background, it's not allowed in IOS. dispatch_async and queues are meant for moving CPU or Network intensive tasks to background for processing to keep UI responsive. They can't be used like listeners – harsha yarabarla Nov 18 '15 at 06:31
  • ok but how to use above code in dispatch_async ?where i need to update my code? what it affects? – Shrikant K Nov 18 '15 at 06:41
  • _"I've heard using dispatch_async we can run code in background."_ Actually, with `dispatch_async` you submit a block for execution on a specified dispatch queue. This is not "running code in background", where "background" is an [application's execution state](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/TheAppLifeCycle/TheAppLifeCycle.html). – CouchDeveloper Nov 18 '15 at 07:25

2 Answers2

1

We can use dispatch_async for.
For example this is downloading some image and storing in UserDefaults in background

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) { () -> Void in
                let imageData = NSData(contentsOfURL: NSURL(string: thankYouImageURL)!)
                if let data = imageData {
                    print("Success Thanks Image")
                    NSUserDefaults.standardUserDefaults().setObject(data, forKey: "registerThanksImage")

                }else{
                    print("failure thanks image")
                }

            }

General Syntax

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
        // do background task
        dispatch_async(dispatch_get_main_queue()) {
            // update some UI
        }
    }
Rajan Maheshwari
  • 14,465
  • 6
  • 64
  • 98
  • In my case in viewDidLoad number of lines are there from there I'm calling twice getContactNames. Now where should i need to change my code? – Shrikant K Nov 18 '15 at 06:45
  • U r calling only once. Its with if else loop.. At a time only one call to getContactNames – Rajan Maheshwari Nov 18 '15 at 06:50
  • Twice!! if first time permission granted and second if permission was already granted. – Shrikant K Nov 18 '15 at 06:52
  • Whenever there is some long task, you use this dispatch_async just like I am downloading some image from server. When the download finishes I have to update my UI and set image in imageView that is done in mainthread. – Rajan Maheshwari Nov 18 '15 at 06:52
  • At a time only one is called..we will get to permission granted. and if u again come to this controller then it will go with already granted – Rajan Maheshwari Nov 18 '15 at 06:54
  • After you are getting contacts, you may be updating some UI. So getContacts will come in background and UIUpdation will come in mainQueue – Rajan Maheshwari Nov 18 '15 at 06:57
  • SO can u please help me ? how i need to update my viewDidLoad ? – Shrikant K Nov 18 '15 at 06:59
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/95410/discussion-between-k-shrikant-and-rajan-maheshwari). – Shrikant K Nov 18 '15 at 07:00
1

There's syntactic sugar in Swift for asynchronous dispatches in Grand Central Dispatch. You can find it here: https://github.com/duemunk/Async

It's very easily to run your code in background.

Just like this:

Async.background {
     println("This is run on the background queue")
}.main {
     println("This is run on the main queue, after the previous block")
}
Joey Wong
  • 185
  • 1
  • 4