Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.

2016-08-01

Adopting Swift 3 | GCD and CoreData in Swift 3

2016-08-17: Note that this post covers Xcode 8 beta 3, the current beta 6 is not compatible with the stuff below.

In the past few days I have been busy upgrading my frameworks (SwifterLog, SwifterJSON, SwifterSockets) and application Swiftfire to Swift 3.
Over all, the migrator does a decent job. It is not flawless but does a good enough job to keep the remaining work to a minimum. It took me about 4 days to upgrade the above mentioned packages.
The job is not finished yet, but I do have a -sort of- running application again.

The three issues that took the most manual work for me is the conversion of Foundation types to build-in Swift types (like NSDate -> Data, NSNumber -> Number, etc) , the adaptation of the new GCD implementation and Core Data.

None of these is difficult per se, but it is a new way of doing thing, thus it takes some time figuring things out.

This is what I learned:

GCD

Creating a new queue:

let acceptQueue = DispatchQueue(label: "Accept queue", attributes: [.serial, .qosUserInteractive])

Quite nice actually. And you get to specify both the nature (serial/concurrent) and the priority at the same time. Though I would have liked the priorities specified differently (lowest, low, normal, high, highest ?)

To execute work on the queue:

acceptQueue.async() {
    acceptAndDispatch(socket: acceptSocket)
    SwifterSockets.closeSocket(acceptSocket)
}

Or you can use the sync() of course.

To time the execution of some work:

let dpt = DispatchTime(uptimeNanoseconds: DispatchTime.now().uptimeNanoseconds + UInt64(delta * Double(NSEC_PER_SEC)))
queue.after(when: dpt) { [weak self] in self?.execute() }

Assuming the delta time is the delay in seconds.

I also updated the synchronization away from p_thread_lock to GCD as suggested:


    public class MyClass {
        
        private var syncQueue = DispatchQueue(label: "MyClass Synch", attributes: [.serial])
        
        public var aDate: Date? {
            get {
                return syncQueue.sync(execute: { return self._aDate })
            }
            set {
                syncQueue.sync(execute: { self._aDate = newValue })
            }
        }
             private var _aDate: Date

Though I am a little weary about creating a new queue for every instance of 'MyClass', I decided that for now I will simply wait and see if that becomes a problem.

Core Data

The first I noticed is that the choice to use scalar types has been moved from the "Edit -> Create..." dialogue to the Data Model Inspector. This makes it possible to decide on a case-by-case if we want to use scalar types or not. The second thing is that the choice between Swift and Objective-C has also moved: from the "Edit -> Create..." dialogue to the File Inspector.

Also in the Data Model Inspector there is a new "Codegen" selection box. By default it is set to "Manual/None" which is the same behaviour as before. I have tried the other settings, but either the selection criteria is a little buggy or I am doing things wrong. I could not get the automatic code generation to work properly. No biggy, that can wait.

Generating the managed object custom classes uses a different naming strategy now: <myname>+CoreDataProperties.swift (as before) and <myname>+CoreDataClass.swift (replaces <myname>.swift)
I moved my code from <myname>.swift to <myname>+CoreDataClass.swift and have not experienced any problems.
It can occur that an extra file is created, I have already forgotten how its called precisely, but that file will not compile. Simply delete it. I have read elsewhere that this only occurs if no "save" of the object model was made before creating the managed objects.

The only bigger chance I had to make was to replace the creation of NSFecthRequest's. That must now be done as follows:

let fetchDomainsRequest = NSFetchRequest<CDDomains>(entityName: "CDDomains")

Also, executing the fetch request is now simpeler:

let domainsArray = try self.managedObjectContext.fetch(fetchDomainsRequest)

No need for type casting, that is now implicit.

While there is a new way to create entities as well, that seems to depend on MacOS 10.12, so I kept the old method.

Happy coding...

Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH

We don't get the world we wish for... we get the world we pay for.

No comments:

Post a Comment