Using AutoLayout with UIView Subclasses in Playgrounds

myview1x

Playgrounds on the Mac and iPad are a great way to develop quick prototypes for new classes. Recently I had the need to create a UIView subclass that contained a few labels. Unfortunately, I couldn’t get my labels to display in the playground. When I used a UIViewController instead of a UIView, everything displayed properly. However, when I changed the parent class to UIView and made the few appropriate changes, my background color changed but my labels no longer appeared. So, instead of seeing this:

view_goal

I was seeing this:

view_problem

My initial thought was to configure the label in layoutSubviews() but the result was still the same.

It turns out that the labels will not autolayout inline within the playground.  You must use the PlaygroundSupport module and the liveView window:

import UIKit
import PlaygroundSupport

class MyView: UIView {

  ...

}

let v = MyView(frame: CGRect(x: 0, y: 0, width: 200, height: 150))
PlaygroundPage.current.liveView = v

Here’s a complete example:

import UIKit
import PlaygroundSupport

class MyView: UIView {
    
    let label = UILabel()
    
    private func setup() {
        self.backgroundColor = UIColor.green

        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "Hello world"
        label.textAlignment = .center
        self.addSubview(label)
        
        let margins = self.layoutMarginsGuide
        
        label.leadingAnchor.constraint(equalTo: margins.leadingAnchor, constant: 0).isActive = true
        label.trailingAnchor.constraint(equalTo: margins.trailingAnchor, constant: 0).isActive = true
        label.topAnchor.constraint(equalTo: margins.topAnchor, constant: 0).isActive = true
        label.bottomAnchor.constraint(equalTo: margins.bottomAnchor, constant: 0).isActive = true
        
    }
    
//    override func layoutSubviews() {
//    }
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()

    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

let v = MyView(frame: CGRect(x: 0, y: 0, width: 200, height: 100))
PlaygroundPage.current.liveView = v
v

Advertisements

Swift Cookbook Updated to Swift 3.0 Syntax

I updated my online Swift Cookbook to the 3.0 syntax.

Here are the current topics:

I also added a Github repo where all the sections are in one playground. In the near future, I hope to add sections for web, regular expressions, and files. Let me know if there are any other topics that interest you.

Functional Swift: Using Array filter and forEach functions

Recently, I started learning a couple of functional languages through online MOOCs:

Swift isn’t classified as a functional language. However, that doesn’t mean we can’t use lessons learned from functional programming to improve our code. In this article, I illustrate a few ways my programming has changed after a couple of weeks of functional programming.

[].filter

There are many places in my code that looked something like this snippet:

self.retestQuestions = []

for q in questionList {
    if !q.isAnsweredCorrectly {
        self.retestQuestions.append(q)
    }
}

This translates to one line of Swift code:

let retestQuestions = questionList.filter({!$0.isAnsweredCorrectly})

In the past, I’ve used filter() to replace NSPredicate statements, which I used extensively in Objective C. In my first conversion to Swift, I directly translated my Objective C to Swift then cast my Swift array back to an NSArray to get the filter to work. Roughly my code looked like this:

let predicate = NSPredicate(format: "numWordsInGroup >= \(minWordCount) and  numPicturesInGroup >= \(minPictureCount)")

let answer = (a1 as NSArray).filtered(using: predicate)

Embracing the Array filter() function makes a lot more sense:

let answer = a1.filter({$0.numWordsInGroup >= minWordCount && $0.numPicturesInGroup >= minPictureCount})

After only a couple of weeks of functional programming, I’ve noticed many places in my code where this example, and other

[].forEach

The forEach() function isn’t a functional concept. However, without going into detail, my functional programming has led me to prefer using the Array forEach function more often. Here are several snippets from my code:

Add subviews to parent

[pronounView, answerWellView, answerConjugationView].forEach {self.mainContainerView.addSubview($0)}

Update: Someone pointed out on Reddit that this can be simplified:

// Simply pass func to apply to each element
[pronounView, answerWellView, answerConjugationView].forEach (mainContainerView.addSubview)

Active constraints

[c1, c2].forEach {NSLayoutConstraint.activate($0)}

Applying the same concept of passing the function as an argument to forEach(), activating constraints is even simpler.

[c1, c2].forEach(NSLayoutConstraint.activate) 

translatesAutoresizingMaskIntoConstraints and addSubviews

[answer1Btn, answer2Btn, answer3Btn, answer4Btn].forEach {
    $0.translatesAutoresizingMaskIntoConstraints = false
    self.cardFrontSubView.addSubview($0)
}

Disable and hide buttons

[answer1Btn,answer1Btn,answer3Btn,answer4Btn].forEach {
    $0.isEnabled = false
    $0.isHidden = false
}

Conclusion

I’ve just finished the second week, of a six week, Haskell MOOC. Hopefully, soon I’ll be using more functional concepts and my code will be “cleaner”, and more importantly contain fewer bugs.

Disabling Activity Tracing in Xcode 8

In Xcode 8, every time you run your app, there is additional logging information in the debugging window that looks similar to this:

2016-09-29 12:37:04.826400 LosVerbos[24208:17542891] subsystem: com.apple.UIKit, category: HIDEventFiltered, enable_level: 0, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 1, privacy_setting: 2, enable_private_data: 0
2016-09-29 12:37:04.833232 LosVerbos[24208:17542891] subsystem: com.apple.UIKit, category: HIDEventIncoming, enable_level: 0, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 1, privacy_setting: 2, enable_private_data: 0
2016-09-29 12:37:04.844944 LosVerbos[24208:17542886] subsystem: com.apple.BaseBoard, category: MachPort, enable_level: 1, persist_level: 0, default_ttl: 0, info_ttl: 0, debug_ttl: 0, generate_symptoms: 0, enable_oversize: 0, privacy_setting: 0, enable_private_data: 0

xcode

While this may be useful at some point, I find that it makes it harder to see my own debugging messages. These messages can be disabled by setting an environment variable in your schema: OS_ACTIVITY_MODE disable

 

schema
More on Apple’s new logging: WWDC 2016 – Session 721 – iOS, macOS – Unified Logging and Activity Tracing

Should I Use Objective C or Swift for Writing iOS Apps?

Simply look at these code snippets:

@import UIKit; // Other imports below
#import “ViewController1.h”
#import “ViewController2.h”
#import “MyDataModel.h”
#import “NoLongerUsed.h”

NSString *s = @”Swift is the future”;
UIViewController *vc = [[UIViewController alloc] init];
UILabel *label1 = [[UILabel alloc] init];
UIButton *button1 = [[UIButton alloc] init];
NSArray *names = @[@”John”, @”Paul”, @”George”, @”Ringo”];
NSDictionary *ages = @{@”John”: @(1940), @”Paul”: @(1942), @”George”: @(1943), @”Ringo”: @(1940)};

vs

import UIKit // No other imports needed

let s = “Swift is the future”
let vc = UIViewController()
let label1 = UILabel()
let button1 = UIButton()
let names = [“John”, “Paul”, “George”, “Ringo”]
let ages = [“John”: 1940, “Paul”: 1942, “George”: 1943, “Ringo”: 1940]

Swift is less visually noisy. Now, imagine 100,000 of code of each language. Which is more maintainable?

Less code and more maintainable code directly translates to a cost savings. The only valid argument developers have is that Swift is still an evolving language so the source will break, at least in the next version. I claim that you’re still better off writing in Swift and fixing any breaking changes than writing in Objective C. You will have done less work and your code will be safer and more maintainable.

By the way, if you want to learn Swift, there’s a lot of information available: books, blogs, and other reference material.

3000 Swift Urls

I recently passed 3000 urls in my Swift Resources database. Over the weekend I added over a 100 YouTube videos. I haven’t tagged everything but I’ll work on it this week.

Since my last writeup in Sept, I’ve added Swift Today, Swift Weekly, and “Tags” pages, which shows all the tags and the tag count.

swift_tags

Finally, I also started a Swift Cookbook with topics that include Strings, Arrays, Dictionaries, and Dates. I’ll be working on additional Cookbook pages over the next few months.

Swift adoption by bloggers has been phenomenal. Most developers and book authors made a quick transition to Swift in the summer of 2014 with iOS 8. Thanks to the community it’s now easy to master iOS using Swift.

Swift: dateFromInt() and intFromDate()

Updated: 20161208 to Swift 3

I needed a couple of convenience functions to convert between NSDates and YYYYMMDD integer dates. Here are examples of each function call:

let d0 = dateFromInt(20160111)
let d1 = intFromDate(Date())

Here’s the source for dateFromInt():

//: Date from Int YYYYMMDD
func dateFromInt(_ date:Int) -> Date {
    
    let year = date / 10000
    let month = date % 10000 / 100
    let day = date % 100
    
    let components = NSDateComponents()
    components.year = year
    components.month = month
    components.day = day
    
    let aDate = NSCalendar(identifier: NSCalendar.Identifier.gregorian)?.date(from: components as DateComponents)
    
    return aDate!
}


Here’s intFromDate()

//: Date to Int YYYYMMDD
func intFromDate(_ date:Date) -> Int {
    
    let calendar = NSCalendar.current
    let components = calendar.dateComponents([.year, .month, .day], from: date)

    let year = components.year
    let month = components.month
    let day = components.day
    
    let intDate = year! * 10000 + month! * 100 + day!
    return intDate
    
}