vankuik.nl

Latest weblog entries

2017-09-17 Replacing NSTimer in Swift 4

For repeated calling of a function, the Timer class is available (used to be called NSTimer). So perhaps you had the following code in your Swift 3 project:

    private var timer: Timer?
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.timer = Timer.scheduledTimer(
            timeInterval: 1.0, target: self,
            selector: #selector(self.timerAction),
            userInfo: nil,
            repeats: true)
    }
    func timerAction() {
        // Do something
    }

When you move your project to Swift 4 (via Xcode 9), then first you get the following warning:

    The use of Swift 3 @objc inference in Swift 4 mode is deprecated. Please address deprecated @objc inference warnings, test your code with “Use of deprecated Swift 3 @objc inference” logging enabled, and then disable inference by changing the "Swift 3 @objc Inference" build setting to "Default" for the "blah" target.

You can fix this warning by updating the project settings and update the code as follows:

    @objc func timerAction() {
        // Do something
    }

For some reason, I don't like seeing that @objc in my projects. There's an alternative, and that's not to use Timer at all, but instead move to GCD:

    private let timer = DispatchSource.makeTimerSource()
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        timer.schedule(deadline: .now(), repeating: 1.0)
        timer.setEventHandler {
            DispatchQueue.main.sync {
                self.timerAction()
            }
        }
        timer.activate()
    }

Have fun with Swift 4 :)

2017-07-25 Swift dictionary keys to array

The following code can be pasted into a Swift playground, and demonstrates how you can get a mutable array of (a copy of the) dictionary keys.

    let dict = ["Fritz": "Senior Engineer",
                "Mary": "Director of Safety",
                "John": "VP of this and that"]
    var keyArray: [String] = dict.keys.map { $0 }
    print(keyArray)
    if let index = keyArray.index(of: "Fritz") {
        keyArray.remove(at: index)
    }
    print(keyArray)

If you don't cast to an array of Strings, you'll get the following error:

    error: value of type 'LazyMapCollection<LazyMapCollection<Dictionary<String, String>, String>, String>' has no member 'remove'

2017-06-07 Make a list of files left after installing software

Sometimes, Mac software is distributed as an installer. Potentially that leaves a bunch of files strewn all over your Mac its filesystem. One tip is to run the following command before installation:

 $ find -x . /  > before.txt

Then install the software, and run it once. Quit, then run the following two commands:

 $ find -x . /  > after.txt
 $ diff before.txt after.txt > filelist.txt

Now open the filelist.txt and you'll see a rough list of all installed files. Both as a result of the installation, but also takes into account whatever the software wrote in your ~/Library folder.

2017-06-06 Always leave a view in a stackview

When you hide/unhide an element in a UIStackView, it will nicely animate. However when you hide the only element in the stackview, the animation will go wrong. To see what happens, run the following project:

https://github.com/bvankuik/NestedStackViewsShowAndHide

Click the "Toggle Visibility" button. Then tap the "Add dummy view" button and try again.

2017-05-29 Creating a Swift module

When creating a custom view, I find it very useful to make it into a framework and include an example project. This enables quickly iterating over the new component. Plus, when you're done, it's very easy to import the result into other projects. To set this up, take the following steps:

  • Create new project, and choose Cocoa Touch Framework
  • Type some name that reflects a library name such that "import yourlibname" looks logical and good
  • Create a new Swift file, and add your code there
  • Then go to menu File -> New -> Target and create a Single View Application
  • Name it YourlibnameExample or something
  • Select the project, then the new target, and in the Embedded Binaries section, click the plus
  • Select the previously created framework, and click Add
  • Then edit the new ViewController and type "import yourlibname"
  • Then instantiate a class from your framework somewhere; no errors should occur

More...

Weblog Archive

Weblog entries 2017

Weblog entries 2016

Weblog entries 2015

Weblog entries 2014

Weblog entries 2013

Weblog entries 2012

Weblog entries 2011

Weblog entries 2010

Weblog entries 2009

Weblog entries 2008

Weblog entries 2007

Weblog entries 2006

Weblog entries 2005

Weblog entries 2004

All weblog entries

Articles

Articles, chronologically (latest first). This is pretty old stuff.

Scribblings

Not yet finished. Maybe will never be finished. Maybe they'll get deleted. Who knows?

Programming:

System administration:

Others:

Files: