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

2016-08-08

The nil case in swift switch statements | Swift Short & Sweet

I am not really sure when this was added or even if this was possible from the beginning, but I just re-discovered a very sweet feature of the switch statement in Swift: The nil case.

enum OneTwo { case one, two }

var ot: OneTwo?

switch ot {
case nil: print("Nil")
case .one?: print("One")
case .two?: print("Two")
}

It even detects the absence of the nil case (when you forget) and asks for a default when you do so.

As near to perfect as it gets imo.

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.

2016-08-06

New versions for SwifterLog, SwifterSockets, SwifterJSON and Swiftfire | Swift 3 adaptation.

2016.08.17: Just upgraded to Xcode 8 beta 6, and lo and behold... have to do it all again...

I just pushed the new versions for SwifterLog (v0.9.12), SwifterSockets (v0.9.6), SwifterJSON (v0.9.10) and Swiftfire (v0.9.13) to github.

All of them upgrades to Swift 3 (beta), so only make the change if you are also working with Swift 3/Xcode 8 beta 3.

All in all I am rather pleased with the changes in Swift 3, they do make the code better. It took me about a week to change all of the above mentioned source code. Which is a lot, so yes, upgrading an existing code base to Swift 3 will cost you some. Worth it or not, that is something only you can decide. For open source projects like the above, it's a no-brainer of course.

So... on and forward to v1.0... :-)

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.

2016-08-04

while let | Swift gotcha

Consider the following:

class LinkedList {
    var previous: LinkedList?
    var next: LinkedList?
    var payload: String
    init(previous: LinkedList?, value: String) {
        self.previous = previous
        payload = value
        previous?.next = self
    }
    func walkBack() -> String {
        var str = payload
        let link = self
        while let link = link.previous {
            str = link.payload + str
        }
        return str
    }

}

It should be clear what the intention is of the function walkBack() is: it should concatenate all payloads and return that as a string.

But the function contains an error that might not bite immediately.

For the top level element of the list, the function wil work fine. It simply returns its own payload.

But for the elements that have a previous element the function will go into an endless loop.

Why? that becomes clear when we change the definition of link from a let to a var:


This shows that the value of link never changes. The while loop creates its own instance of link each time it loops. And since the value for that link is derived from the value of the link outside the loop it will loop until the app runs out of memory.

Simply replacing the outside-the-loop definition of link to "outsideLink" clarifies this better:

    func walkBack() -> String {
        var str = payload
        let outsideLink = self
        while let link = outsideLink.previous {
            str = link.payload + str
        }
        return str

    }

Now it is clear that link is never modified to anything else but the previous element of self. In fact we could better write this as:

    func walkBack() -> String {
        var str = payload
        while let link = self.previous {
            str = link.payload + str
        }
        return str
    }

Which of course we would never do since the error is now obvious!

The tricky thing is of course that we (I?) get used to simply accepting the suggestions of the compiler.

Lesson for self: Don't automatically accept the compiler suggestions!

Oh, and btw, the right way to do this is:

    func walkBack() -> String {
        var str = payload
        var link = self.previous
        while link != nil {
            str = link!.payload + str
            link = link!.previous
        }
        return str

    }

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.

2016-08-02

Missing "remove" operation on Data in Swift 3 | An Extension for the Data type in Swift 3

It could be me, but is anyone missing the "remove" operation on the "Data" type in Swift 3?

Well, there is an extension for that:

extension Data {

    mutating func removeSubrange(_ range: Range<Int>) {
        var dummy: UInt8 = 0
        let empty = UnsafeBufferPointer<UInt8>(start: &dummy, count: 0)
        self.replaceSubrange(range, with: empty)
    }
}

Example usage:

var buffer = Data(bytes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
let range = Range(uncheckedBounds: (lower: 1, upper: 5))
buffer.removeSubrange(range)

Output: <00050607 0809>

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.

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.