RecentChanges 2015-03-06 XML TXT

Latest weblog entries

2015-02-06 Swift enum raw values as an array

Here's a quick example of using Swift's map() function. Here it's used to put the raw values of an enum into an array. Paste this into a playground to see the result.

	import Cocoa
	enum ContentType : Int {
		case Unknown = 0
		case PAS = 1
		case PASGENERIC = 2
		case PASROUTE = 3
		case PASBUNDLE = 4
		case TOPIC = 5
		case NEWS = 6
	let contentTypeArray = [ContentType.PAS, ContentType.PASROUTE, ContentType.TOPIC]
	let intArray ={type in type.rawValue})

Even shorter:

	let intArray ={$0.rawValue})

How it looks in a playground:

swift enum raw values as array playground.png

2015-02-05 Swift example of a batch update in Core Data

Here's a Swift example of doing a batch update in Core Data:

	let updateRequest = NSBatchUpdateRequest("some_entity_name")
	let predicateIsRead = NSPredicate(format: "isRead = %@", NSNumber(bool: true))
	updateRequest.predicate = predicateIsRead
	updateRequest.propertiesToUpdate = [
		ContentItemAttributes.isRead.rawValue: NSNumber(bool: false)
	updateRequest.resultType = NSBatchUpdateRequestResultType.UpdatedObjectsCountResultType
	var error: NSError?
	let updateResult = objectContext.executeRequest(updateRequest, error: &error) as NSBatchUpdateResult?
	if let result = updateResult {
		let count = result.result as Int
		println("Updated \(count) rows")
	} else {
		println("Error during batch update: \(error?.localizedDescription)")

Note that you'll need to update the objects in memory. The above code just prints the row count. If you have stuff displayed in the user interface, use this answer on Stack Overflow to adjust the above code.

2015-02-01 Layout of a tableviewcell depending upon device orientation

Last week, a refresh of the design of my client's app called for a layout that changed depending on the device orientation. We're using AutoLayout and didn't want to use any deprecated methods.

Problem was that it called for layout changes within a UITableViewCell. I thought of a way to do this with AutoLayout but the constraints would become quite complex. Instead, I took the following approach:

  • Create a custom UITableViewCell by subclassing it
  • To this subclass, add outlets for the constraints that you want to influence
  • In the view controller, detect whether we're in portrait or landscape, then update the constraints of the cells using the IBOutlet properties

Thus the UITableViewCell subclass looks as follows:

	class CustomTableCell : UITableViewCell {
		@IBOutlet weak var dateLabel: UILabel!
		@IBOutlet weak var nameLabel: UILabel!
		@IBOutlet weak var trailingConstraint: NSLayoutConstraint!

Problem is: where can you set properties all the currently visible cells? The easiest way I could come up with, is in the cellForRowAtIndexPath() function. The view controller class has the following property:

	var size: CGSize = CGSizeZero

The viewWillTransitionToSize() function stores the new screen size and asks the UITableView to reload:

	override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
		super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
		self.size = size
		NSLog("viewWillTransitionToSize self.size = \(self.size)")

And when dequeueing new cells, we set the constraint its constant:

	override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
		let cell = tableView.dequeueReusableCellWithIdentifier("TestCell") as CustomTableCell!
		cell.nameLabel.text = self.items[indexPath.row]
		if self.size.width > self.size.height { //Landscape
			cell.trailingConstraint.constant = 100
		} else { //Portrait
			cell.trailingConstraint.constant = 0
		return cell

Because viewWillTransitionToSize() is not called when the View Controller is run for the first time, I also added the following code to viewWillLayoutSubviews():

	override func viewWillLayoutSubviews() {
		// Only run once, upon first display
		if self.size == CGSizeZero {
			self.size = self.tableView!.frame.size
			NSLog("viewWillLayoutSubviews self.size = \(self.size)")

layout uitableviewcell depending upon device orientation.gif

Download the example project:

Note: I created the above truly breathtaking animated gif by taking a screen recording with QuickTime Player, running the iOS Simulator, then converting the resulting .mov file with the following ffmpeg command:

  ffmpeg -i -r 15 example.gif

ffpmeg was installed via Homebrew.

2015-01-29 Update interface when app is opened

If you're developing in Swift and want to update your app's interface when it's reopened, put the following piece of code in the App Delegate:

	var appLastUsedTime = CFAbsoluteTimeGetCurrent()
	func applicationWillEnterForeground(application: UIApplication) {
		let timeSinceLastUsage = CFAbsoluteTimeGetCurrent() - self.appLastUsedTime
		log.verbose("App last used \(timeSinceLastUsage) seconds ago")
		//If it's been at least a day since the user accessed the app, send out a notification
		if timeSinceLastUsage > (24 * 60 * 60) {
			log.verbose("Posting notification \(MYFApplicationDidBecomeActiveAfterTimeoutNotification)")
			NSNotificationCenter.defaultCenter().postNotificationName(MYFApplicationDidBecomeActiveAfterTimeoutNotification, object: nil)
			self.appLastUsedTime = CFAbsoluteTimeGetCurrent()

Above the App Delegate, add the following global:

    let ApplicationDidBecomeActiveAfterTimeoutNotification = "ApplicationDidBecomeActiveAfterTimeoutNotification"

In the view controller, add the following code in viewWillAppear():

	NSNotificationCenter.defaultCenter().addObserver(self, selector: "updateInterface",
			name: ApplicationDidBecomeActiveAfterTimeoutNotification, object: nil)

And the following code in viewDidDisappear()

	NSNotificationCenter.defaultCenter().removeObserver(self, name: ApplicationDidBecomeActiveAfterTimeoutNotification, object: nil)

Note that this notification doesn't trigger when activating the app for the first time. If you need that, add the following code to the view controller in question, in its viewDidAppear() function:

	if !self. didInitializeAtStartup {
		didInitializeAtStartup = true

And the following class member variable:

    	private var didInitializeAtStartup = false

2015-01-20 button title truncated

There's a weird situation that when you add an image to a standard UIButton and add some space between the image and the label, the label text gets truncated:

moreinfo 1.png

The reason is that you used the image edge inset. This edge inset is not used to calculate the intrinsic button size.

For the correct steps, check my answer on StackOverflow.


Weblog Archive

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, chronologically (latest first). This is pretty old stuff.


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


System administration: