Tuesday, March 31, 2015

Gradient UINavigationBar in Swift

Here's how to make a gradient NavBar in Swift, taken mainly from this <a href="http://stackoverflow.com/questions/494982/uinavigationbar-tintcolor-with-gradient">SO post</a>: First create an extension for CAGradientLayer Here's how to make a gradient NavBar in Swift:
First create an extension for CAGradientLayer (need to add Quartz library)
extension CAGradientLayer {
    class func gradientLayerForBounds(bounds: CGRect) -> CAGradientLayer {
        var layer = CAGradientLayer()
        layer.frame = bounds
        layer.colors = [UIColor.redColor().CGColor, UIColor.blueColor().CGColor]
        return layer
    }
}
Use whatever colors suit your needs.
Then in your overriden NavController class (so many ways to do this, I chose to set it up in the NavController subclass used everywhere in my app),
private func imageLayerForGradientBackground() -> UIImage {

    var updatedFrame = self.navigationBar.bounds
    // take into account the status bar
    updatedFrame.size.height += 20
    var layer = CAGradientLayer.gradientLayerForBounds(updatedFrame)
    UIGraphicsBeginImageContext(layer.bounds.size)
    layer.renderInContext(UIGraphicsGetCurrentContext())
    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return image
}
In your viewDidLoad of the NavController subclass:
override func viewDidLoad() {
        super.viewDidLoad()
        self.navigationBar.translucent = false
        self.navigationBar.tintColor = UIColor.whiteColor()
        let fontDictionary = [ NSForegroundColorAttributeName:UIColor.whiteColor() ]
        self.navigationBar.titleTextAttributes = fontDictionary
        self.navigationBar.setBackgroundImage(imageLayerForGradientBackground(), forBarMetrics: UIBarMetrics.Default)
    }
I did some whitening to the tint and title text, mainly because any gradient you have, white would probably work best.
Here's the current app I'm working on with the gradient colors of my choice:

Sunday, March 29, 2015

C# Model Object builder

A nice online tool to build C# model objects based off JSON text you feed it.

http://json2csharp.com/

How to shuffle an array in Swift

4-2-2015 This was imported over from my roon.io blog that's now been closed down.

Had the challenge and time limit put to me the other day so here’s my working solution:
func shuffleArray(array: [Int]) -> [Int] {
    
    var tempArray = array
    for index in 0...array.count - 1 {
        let randomNumber = arc4random_uniform(UInt32(myArray.count - 1))
        let randomIndex = Int(randomNumber)
        tempArray[randomIndex] = array[index]
    }
    
    return tempArray
}

shuffleArray(myArray)
shuffleArray(myArray)
shuffleArray(myArray)

Parsing a date out of JSON in Swift

For most of the APIs you'll deal with you'll get the date back in a For most of the APIs you'll deal with you'll get the date back in a format like this:
date:1420420409680
In Objective-C it was pretty easy assume the interval is the value above,
NSDate *date = [NSDate dateWithTimeIntervalSince1970:interval/1000.0];

NSDateFormatter* df_local = [[NSDateFormatter alloc] init];
[df_local setTimeZone:[NSTimeZone timeZoneWithName:@"CST"]];
[df_local setDateFormat:@"MM-dd"];    

NSString* ts_local_string = [df_local stringFromDate:date];
This would give you a formatted date string in the timezone you request.
In Swift it wasn't as straight forward.
Originally I attempted this:
var meetups = [Meetup]()
for meetupDictionary in (meetupsJsonArray as Array<Dictionary<String, AnyObject>>) {
    let eventName = meetupDictionary[self.nameKey]! as String
    let eventId = meetupDictionary[self.idKey]! as String
    let timeValue = meetupDictionary[self.timeKey]! as Int
    let timeValueAsDouble = Double(timeValue/1000.0)
    let date = NSDate(timeIntervalSince1970: timeValueAsDouble)
    let meetup = Meetup(title: eventName, eventId: eventId, date: date)
    meetups.append(meetup)
}
That worked, actually (well not the timezoning, but the date-time anyway).
But only on a 64 bit device/simulator. On an iPhone 5/4s it was giving a strange value for the year. As you would guess, it had to do with as Int. I won't explain it here, but the blog sketchyTech explains how numbers and primitives are handled in Swift.

Swift by the numbers, the long and short of it

The correct way was to change the time parsing lines to this:
let timeValueAsNSNumber = meetupDictionary[self.timeKey]! as NSNumber
let timeValue = timeValueAsNSNumber.doubleValue/1000.0
let date = NSDate(timeIntervalSince1970: timeValue)
Even with the new offerings of Swift, you still have to use aspects of the CocoaTouch framework like NSNumber. This gave the correct date and time on a 32 and 64 bit devices.