Generic Alert Method

Here is a generic alert method that you can place in a global functions/variables file that checks for an existing alert first.

func showAlert(withTitle title: String, message: String, viewController: UIViewController) {
    if viewController.presentedViewController == nil { // Prevent multiple alerts at the same time
        let localizedTitle = NSLocalizedString(title, comment: "")
        let localizedMessage = NSLocalizedString(message, comment: "")
        let alert = UIAlertController(title: localizedTitle, message: localizedMessage, preferredStyle: .Alert)
        let action = UIAlertAction(title: "OK", style: .Default, handler: nil)
        alert.addAction(action)
        
        viewController.presentViewController(alert, animated: true, completion: nil)
    }
}

 

Get Timestamps

This is just a random method I’m no longer using and wanted to get rid of but didn’t really want to throw it away in case I want to reference it someday.

static func getTimestamps(forEntry entry: Entry?) -> [String: Int] {
    let calendar = NSCalendar.currentCalendar()
    let formatter = NSDateFormatter()
    formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
    var since = NSDate()
    var until = NSDate()
    
    if let entry = entry {
        if let createdAt = entry.created_at {
            // get date portion only of createdAt
            let entryDateComponents = calendar.components([.Day, .Month, .Year], fromDate: createdAt)
            
            // set the time to midnight and the last second
            let entryDateBegin = "\(entryDateComponents.year)-\(entryDateComponents.month)-\(entryDateComponents.day) 00:00:00"
            let entryDateEnd = "\(entryDateComponents.year)-\(entryDateComponents.month)-\(entryDateComponents.day) 23:59:59"
            
            since = formatter.dateFromString(entryDateBegin)!
            until = formatter.dateFromString(entryDateEnd)!
        }
    } else {
        let currentDateComponents = calendar.components([.Day, .Month, .Year], fromDate: NSDate())
        let currentDateBegin = "\(currentDateComponents.year)-\(currentDateComponents.month)-\(currentDateComponents.day) 00:00:00"
        let currentDateEnd = "\(currentDateComponents.year)-\(currentDateComponents.month)-\(currentDateComponents.day) 23:59:59"
        
        since = formatter.dateFromString(currentDateBegin)!
        until = formatter.dateFromString(currentDateEnd)!
    }
    
    let sinceTimestamp = Int(since.timeIntervalSince1970)
    let untilTimestamp = Int(until.timeIntervalSince1970)
    
    return ["since": sinceTimestamp, "until": untilTimestamp]
}

 

Add Share Button to iOS 9 App

@IBAction func export(sender: UIBarButtonItem) {        
    if let data = prepareCSVData() {
        let filename = getDocumentsDirectory().stringByAppendingPathComponent("data.csv")
        
        data.writeToFile(filename, atomically: true)
        
        let url = NSURL(fileURLWithPath: filename)
        
        let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
        
        if let popoverController = activityViewController.popoverPresentationController {
            popoverController.barButtonItem = sender
        }

        presentViewController(activityViewController, animated: true, completion: nil)

    } else {
        NSLog("Unable to prepare data")
    }
}

The important line is where you set up the popoverController. Without that, it will crash on iPad.

Send Mail with Attachment in iOS

if MFMailComposeViewController.canSendMail() {
    let data = prepareCSVData()
    
    let mailController = MFMailComposeViewController()
    mailController.mailComposeDelegate = self
    mailController.setSubject("Data Export")
    mailController.setMessageBody("Attached is a CSV file containing your data.", isHTML: false)
    
    // Add attachment
    if let data = data {
        mailController.addAttachmentData(data, mimeType: "text/comma-separated-values", fileName: "headaches.csv")
        
        presentViewController(mailController, animated: true, completion: nil)
    } else {
        NSLog("No data")
    }
}

 

Prevent “Array index out of range” Error in Swift

If you don’t know if the array index you are calling exists, here is a nice way to just return nil instead of an error. I grabbed this from StackOverflow but unfortunately lost the link. I am putting it here because I use it once in a while and get tired of searching for it.

extension Array {
    subscript (safe index: Int) -> Element? {
        return indices ~= index ? self[index] : nil
    }
}

Use it like this:

array.item[safe: 1]

 

Scroll to the Bottom of a Collection View

private func scrollToBottom() {
    let lastSectionIndex = (collectionView?.numberOfSections())! - 1
    let lastItemIndex = (collectionView?.numberOfItemsInSection(lastSectionIndex))! - 1
    let indexPath = NSIndexPath(forItem: lastItemIndex, inSection: lastSectionIndex)
       
    collectionView!.scrollToItemAtIndexPath(indexPath, atScrollPosition: UICollectionViewScrollPosition.Bottom, animated: false)
}

 

Add a UITableView to an Existing ViewController in Xcode

Quick and dirty checklist for adding a table view to an existing view controller:

  1. Embed existing view controller in a NavigationController
  2. Drag a UITableView object into the view controller in the storyboard
  3. Make the UITableView the same width and height as the view controller and set the constraints to all four sides with no margins
  4. Create an outlet and connection for the tableView in the view controller class
  5. Add UITableViewDataSource and UITableViewDelegate to the class declaration. Your class should look something like this
    import UIKit
     
    class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
     
        @IBOutlet weak var tableView: UITableView!
         
        override func viewDidLoad() {
            super.viewDidLoad()
        }
     
    }
  6. Select the table view, open the connections inspector and connect the table view’s dataSource and delegate methods to the View Controller object.
  7. If you’re not using static cells, open the attributes inspector and set the number of Prototype Cells to 1