I am developing a simple reminders app and I've run into some trouble with the Today Extension. The extension works perfectly on my iPad and in the simulator, however on my iPhone it flashes twice before displaying an "Unable to Load" message. I believe it is caused by some sort of memory problem, as didRecieveMemoryWarning was called in one of my debug sessions, however usually the only console output I receive is that "Program ended with exit code: 0." Any help would be greatly appreciated. Here is my code for the Today Extension:
import UIKit
import NotificationCenter
class TodayViewController: UITableViewController, NCWidgetProviding {
let repeatTitles = ["No Repeat", "Repeat Every Minute", "Repeat Hourly", "Repeat Daily", "Repeat Weekly", "Repeat Monthly", "Repeat Annually", "Repeat Monthly Week Number", "Repeat Annual Week Number"]
var mainColor = UIColor(colorLiteralRed: 57/255, green: 181/255, blue: 74/255, alpha: 1.0)
var secondColor = UIColor(colorLiteralRed: 95/255, green: 147/255, blue: 196/255, alpha: 1.0)
var objects = [NSArray]()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
print("MEMORY WARNING NC")
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)
let object = objects[indexPath.row] as NSArray
if object[7] as! String == "CREATEONE" || object[7] as! String == "MOREMEMOS" {
cell.detailTextLabel!.text = object[2] as? String
cell.detailTextLabel!.textColor = secondColor
cell.detailTextLabel!.font = UIFont.systemFontOfSize(16)
}
else {
cell.textLabel!.text = object[2] as? String
if let theDateToStore = object[4] as? NSDate {
if object[6] as! Bool == true {
if (object[3] as! String).stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) == "" {
cell.detailTextLabel!.text = "Memo Muted"
}
else {
cell.detailTextLabel!.text = "Memo Muted- \(object[3] as! String)"
}
}
else {
let timestamp = NSDateFormatter.localizedStringFromDate(theDateToStore, dateStyle: .ShortStyle, timeStyle: .ShortStyle)
let repeatTitle = repeatTitles[(object[5] as? Int)!]
if (object[3] as! String).stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) == "" {
cell.detailTextLabel!.text = "\(timestamp): \(repeatTitle)"
}
else {
cell.detailTextLabel!.text = "\(timestamp): \(repeatTitle)- \(object[3] as! String)"
}
}
}
else {
if (object[3] as! String).stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) == "" {
cell.detailTextLabel!.text = "Memo Muted"
}
else {
cell.detailTextLabel!.text = "Memo Muted- \(object[3] as! String)"
}
}
cell.textLabel!.textColor = mainColor
cell.detailTextLabel!.textColor = UIColor.whiteColor()
}
return cell
}
func updateWithChanges(){
var newObjects = NSUserDefaults(suiteName: "group.Me.MemosApp")!.objectForKey("cashedMemos") as? [NSArray]
if newObjects == nil {
newObjects = [NSArray]()
}
else {
if newObjects!.count > 5 {
for i in stride(from: newObjects!.count - 1, through: 5, by: -1) {
newObjects!.removeAtIndex(i)
}
newObjects!.append([0, true, "More Memos", "", "", 0, false, "MOREMEMOS"])
}
}
newObjects!.append([0, true, "Create a New Memo", "", "", 0, false, "CREATEONE"])
objects = newObjects!
newObjects = nil
tableView.reloadData()
updatePreferredContentSize()
}
override func viewWillAppear(animated: Bool) {
updateWithChanges()
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
if let object = objects[indexPath.row] as NSArray? {
if object[7] as! String == "CREATEONE" {
self.extensionContext?.openURL(NSURL(string: "MemosApp://createMemo")!, completionHandler: nil)
}
else if object[7] as! String == "MOREMEMOS" {
self.extensionContext?.openURL(NSURL(string: "MemosApp://moreMemosFromNC")!, completionHandler: nil)
}
else {
let idNum = object[0] as! Int
let deviceID = object[7] as! String
let memoID = "m\(idNum)\(deviceID)"
self.extensionContext?.openURL(NSURL(string: "MemosApp://openMemo?\(memoID)")!, completionHandler: nil)
}
}
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
func widgetPerformUpdateWithCompletionHandler(completionHandler: ((NCUpdateResult) -> Void)) {
completionHandler(NCUpdateResult.NoData)
}
func widgetMarginInsetsForProposedMarginInsets
(defaultMarginInsets: UIEdgeInsets) -> (UIEdgeInsets) {
return UIEdgeInsetsZero
}
func updatePreferredContentSize() {
preferredContentSize = CGSizeMake(CGFloat(0), CGFloat((objects.count * 50) - 1))//+ tableView.sectionFooterHeight)
}
}
The Today Extension loads a cashed array of memos from an object in an NSUserDefaults shared group. The code is written in Swift 2.0.
It turned out I had created an extra UILabel in the base cell for the tableView (used to make the cell clickable despite having a transparent background in the NC) and the long length of this label was causing the widget to use too much memory.