Swift does not conform to protocol 'OS_dispatch_queue' - swift2

I'm trying to implement an asynchronous function as told in this topic but I always get the following error from Xcode : Type 'dispatch_queue_t!' does not conform to protocol 'OS_dispatch_queue'
Here's my code:
#IBAction func buyButton(sender: AnyObject) {
// get wanted symbol
let symbol = symbolField.text!
// get price of share
var priceShare :Double = 0
_ = lookup(symbol) { name, symbol, price in
dispatch_async(dispatch_get_main_queue()) {
priceShare = price
}
}
buy(symbol, number: 1, price: priceShare)
}
Here's the lookup function:
func lookup(entry : NSString, completion: ((name :String, symbol :String, price :String) -> Void)) {
// define return values
var name = String()
var symbol = String()
var price = String()
// define URL
let url = NSURL(string: "http://yahoojson.gobu.fr/symbol.php?symbol=\(entry)")!
let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in
if let urlContent = data {
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(urlContent, options: NSJSONReadingOptions.MutableContainers)
name = jsonResult["name"] as! String
symbol = jsonResult["symbol"] as! String
price = jsonResult["price"]!!.stringValue as String
completion(name: name, symbol: symbol, price: price)
} catch {
print(error)
}
}
}
// run the task
task.resume()
}
Any hint on what I could be doing wrong?

I figure it out by myself. There was a bug inside on my code.
On the line
priceShare = price
I needed to put
priceShare = Double(price)!
since priceShare require a Double. Don't understand why Xcode didn't tell me so.

Related

Storing/retriving a Codable Dictionary of structs in UserDefaults doesn't work for me

Swift (v 5/5.1) newbie here, having a hard time with Codables...hoping to get some advise from the experts here.
Okay, I have a simple dictionary from struct where the key is a string. I want to store the dictionary in UserDefaults (and later retrieve). There are some quite similar questions here, but these are mainly addressing nested struct's.
First attempt (error handling removed for simplicity):
public struct PriceStruct:Codable {
var myPrice: Double
var myTime: TimeInterval
var selected: Bool
var direction: Int
var myHigh, myLow: Double
enum CodingKeys: String, CodingKey {
case myPrice = "myPrice"
case myTime = "myTime"
case selected = "selected"
case direction = "direction"
case myHigh = "myHigh"
case myLow = "myLow"
}
}
var myPrices: [String: PriceStruct] = [:]
// [fill myPrices with some data...]
func savePrices() {
// error: Attempt to set a non-property-list object
UserDefaults.standard.set(myPrices, forKey: "prices")
}
func loadPrices() {
// obviously this doesn't work either
let myPrices = UserDefaults.standard.data(forKey: "prices")
}
While I assumed from the documentation, that UserDefaults is capable of storing dictionaries, it doesn't - at least for me.
Next thing I tried was using JSONEncoder like this:
// this time with prior JSON encoding
func savePrices() {
// this works
let json = try! JSONEncoder().encode(myPrices)
UserDefaults.standard.set(json as Data, forKey: "prices")
}
func loadPrices() {
// this doesn't work
let json = UserDefaults.standard.data(forKey: "prices")
let decoder = JSONDecoder()
let decoded = try! decoder.decode(PriceStruct.self, from json!)
}
Unfortunately I'm getting an error when trying to load data back from UserDefaults:
Swift.DecodingError.keyNotFound(CodingKeys(stringValue: "myPrice", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"myPrice\", intValue: nil) (\"myPrice\").", underlyingError: nil))
Other variants I tried is converting the encoded JSON to an UTF8 encoded string and storing/retrieving this one:
func savePrices() {
// this works too
let json = try! JSONEncoder().encode(myPrices)
UserDefaults.standard.set(String(data: json, encoding: .utf8), forKey: "prices")
}
func loadPrices() {
// and this doesn't work either
let json = UserDefaults.standard.string(forKey: "prices")!.data(using: .utf8)
}
So, from the error raised, CodingKeys seems to be the root of the problem. I tried to switch over using NSKeyedArchiver and NSKeyedUnarchiver` with no success.
I'm really wondering if there is a simple/universal solution to save/load a Dictionary in UserDefaults?
All your comments and suggestions are appreciated. Thanks!
I tried with the below code in my project that will work for me.
User Model
public protocol UserModel: Codable, PrimaryKey {
var id: String { get }
var firstName: String? { get }
var lastName: String? { get }
var userName: String? { get }
var emails: [String] { get }
}
public struct User: UserModel {
public let id: String
public let firstName: String?
public let lastName: String?
public let userName: String?
public let emails: [String]
public enum CodingKeys: String, CodingKey {
case id = "Id"
case firstName = "FirstName"
case lastName = "LastName"
case userName = "UserName"
case emails = "Emails"
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
self.id = try container.decode(String.self, forKey: .id)
self.firstName = try container.decodeIfPresent(String.self, forKey: .firstName)
self.lastName = try container.decodeIfPresent(String.self, forKey: .lastName)
self.userName = try container.decodeIfPresent(String.self, forKey: .userName)
self.emails = try container.decodeIfPresent([String].self, forKey: .emails) ?? []
}
catch let error {
debugPrint(error)
throw error
}
}
}
I have stored in userDefault using below way
User Data Class
class UserData: NSObject
{
let userDefaultKey = "user_information"
var userData: User?
func getDictionary() -> [String: Data]
{
var dicInfo = [String: Data]()
do
{
let _userData = try JSONEncoder().encode(userData)
dicInfo["userData_default"] = _userData
}catch let error{
print("error while save data in User Default: \(error.localizedDescription)")
}
return dicInfo
}
func saveToDefault()
{
let userDefault = UserDefaults.standard
userDefault.set(getDictionary(), forKey: userDefaultKey)
userDefault.synchronize()
}
func loadFromDefault()
{
let userDefault = UserDefaults.standard
if let dicInfo = userDefault.object(forKey: userDefaultKey) as? [String: Data]
{
update(dicInfo)
}
}
func update(_ dictionaryInfo: [String: Data])
{
do
{
if let _userData_data = dictionaryInfo["userData_default"]
{
if let _userData = try? JSONDecoder().decode(User.self, from: _userData_data) {
userData = _userData
}
}
saveToDefault()
}catch let error{
print("error while load From Default data in User Default: \(error.localizedDescription)")
}
}
}
Hope this will help you.

self is immutable

I have a class, Task, with a 'count' property. The end goal is to increase the count by 1.
In a playground, this is working:
class Task: NSObject {
var name: String
var count: Int
init(name:String, count:Int) {
self.name = name
self.count = count
}
}
var test = Task(name: "test", count: 0)
test.count += 1
// => 1
But in my actual project, it's getting this error:
Left side of mutating operator isn't mutable: 'self' is immutable
In my ViewController, I have an #IBAction function that I'd like to trigger the count increase, so that's where the error is occurring. Here's a trimmed down version:
#IBAction func addTask(sender: AnyObject) {
currentTask = newTaskInput.stringValue
let x = Task(name: currentTask, count: 0)
currentTaskObj = x
// error occurs here
currentTaskObj!.count += 1
}
Any idea how to fix this? I must be missing something because it's working in a playground exactly how I'd like. Huge thanks in advance!
Edit: here's the actual class from my project (I changed sessions to count for the examples above):
class Task: NSObject, NSCoding {
var name: String
var sessions: Int
var time: String = ""
init(name:String, sessions:Int, time:String? = "") {
self.name = name
self.sessions = sessions
self.time = time!
}
required convenience init(coder aDecoder: NSCoder) {
var name = aDecoder.decodeObjectForKey("name") as! String
var sessions = aDecoder.decodeObjectForKey("sessions") as! Int
var time = aDecoder.decodeObjectForKey("time") as! String
self.init(name: name, sessions: sessions, time: time)
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(self.name, forKey: "name")
aCoder.encodeObject(self.sessions, forKey: "sessions")
aCoder.encodeObject(self.time, forKey: "time")
}
}

Swift 3.0 NSFetchRequest error [duplicate]

In Swift 2 the following code was working:
let request = NSFetchRequest(entityName: String)
but in Swift 3 it gives error:
Generic parameter "ResultType" could not be inferred
because NSFetchRequest is now a generic type. In their documents they wrote this:
let request: NSFetchRequest<Animal> = Animal.fetchRequest
so if my result class is for example Level how should I request correctly?
Because this not working:
let request: NSFetchRequest<Level> = Level.fetchRequest
let request: NSFetchRequest<NSFetchRequestResult> = Level.fetchRequest()
or
let request: NSFetchRequest<Level> = Level.fetchRequest()
depending which version you want.
You have to specify the generic type because otherwise the method call is ambiguous.
The first version is defined for NSManagedObject, the second version is generated automatically for every object using an extension, e.g:
extension Level {
#nonobjc class func fetchRequest() -> NSFetchRequest<Level> {
return NSFetchRequest<Level>(entityName: "Level");
}
#NSManaged var timeStamp: NSDate?
}
The whole point is to remove the usage of String constants.
I think i got it working by doing this:
let request:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Level")
at least it saves and loads data from DataBase.
But it feels like it is not a proper solution, but it works for now.
The simplest structure I found that works in 3.0 is as follows:
let request = NSFetchRequest<Country>(entityName: "Country")
where the data entity Type is Country.
When trying to create a Core Data BatchDeleteRequest, however, I found that this definition does not work and it seems that you'll need to go with the form:
let request: NSFetchRequest<NSFetchRequestResult> = Country.fetchRequest()
even though the ManagedObject and FetchRequestResult formats are supposed to be equivalent.
Here are some generic CoreData methods that might answer your question:
import Foundation
import Cocoa
func addRecord<T: NSManagedObject>(_ type : T.Type) -> T
{
let entityName = T.description()
let context = app.managedObjectContext
let entity = NSEntityDescription.entity(forEntityName: entityName, in: context)
let record = T(entity: entity!, insertInto: context)
return record
}
func recordsInTable<T: NSManagedObject>(_ type : T.Type) -> Int
{
let recs = allRecords(T.self)
return recs.count
}
func allRecords<T: NSManagedObject>(_ type : T.Type, sort: NSSortDescriptor? = nil) -> [T]
{
let context = app.managedObjectContext
let request = T.fetchRequest()
do
{
let results = try context.fetch(request)
return results as! [T]
}
catch
{
print("Error with request: \(error)")
return []
}
}
func query<T: NSManagedObject>(_ type : T.Type, search: NSPredicate?, sort: NSSortDescriptor? = nil, multiSort: [NSSortDescriptor]? = nil) -> [T]
{
let context = app.managedObjectContext
let request = T.fetchRequest()
if let predicate = search
{
request.predicate = predicate
}
if let sortDescriptors = multiSort
{
request.sortDescriptors = sortDescriptors
}
else if let sortDescriptor = sort
{
request.sortDescriptors = [sortDescriptor]
}
do
{
let results = try context.fetch(request)
return results as! [T]
}
catch
{
print("Error with request: \(error)")
return []
}
}
func deleteRecord(_ object: NSManagedObject)
{
let context = app.managedObjectContext
context.delete(object)
}
func deleteRecords<T: NSManagedObject>(_ type : T.Type, search: NSPredicate? = nil)
{
let context = app.managedObjectContext
let results = query(T.self, search: search)
for record in results
{
context.delete(record)
}
}
func saveDatabase()
{
let context = app.managedObjectContext
do
{
try context.save()
}
catch
{
print("Error saving database: \(error)")
}
}
Assuming that there is a NSManagedObject setup for Contact like this:
class Contact: NSManagedObject
{
#NSManaged var contactNo: Int
#NSManaged var contactName: String
}
These methods can be used in the following way:
let name = "John Appleseed"
let newContact = addRecord(Contact.self)
newContact.contactNo = 1
newContact.contactName = name
let contacts = query(Contact.self, search: NSPredicate(format: "contactName == %#", name))
for contact in contacts
{
print ("Contact name = \(contact.contactName), no = \(contact.contactNo)")
}
deleteRecords(Contact.self, search: NSPredicate(format: "contactName == %#", name))
recs = recordsInTable(Contact.self)
print ("Contacts table has \(recs) records")
saveDatabase()
This is the simplest way to migrate to Swift 3.0, just add <Country>
(tested and worked)
let request = NSFetchRequest<Country>(entityName: "Country")
Swift 3.0 This should work.
let request: NSFetchRequest<NSFetchRequestResult> = NSManagedObject.fetchRequest()
request.entity = entityDescription(context)
request.predicate = predicate
I also had "ResultType" could not be inferred errors. They cleared once I rebuilt the data model setting each entity's Codegen to "Class Definition". I did a brief writeup with step by step instructions here:
Looking for a clear tutorial on the revised NSPersistentContainer in Xcode 8 with Swift 3
By "rebuilt" I mean that I created a new model file with new entries and attributes. A little tedious, but it worked!
What worked best for me so far was:
let request = Level.fetchRequest() as! NSFetchRequest<Level>
I had the same issue and I solved it with the following steps:
Select your xcdatamodeld file and go to the Data Model Inspector
Select your first Entity and go to Section class
Make sure that Codegen "Class Definition" is selected.
Remove all your generated Entity files. You don't need them anymore.
After doing that I had to remove/rewrite all occurences of fetchRequest as XCode seem to somehow mix up with the codegenerated version.
HTH
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func loadItemsCategory() {
let request: NSFetchRequest<Category> = Category.fetchRequest()
do {
categoryArray = try context.fetch(request)
} catch {
print(error)
}
tableView.reloadData()
}

Parse.com - Download Objects From Database - Show Progress With ProgressBlock

I have Parse class called Product that has 238 rows. Note that this class is not the Parse.com implementation of Product, it is a custom class implemented by myself, as I didn't require all the columns Parse adds to their Product class.
The Product class has a Pointer column (basically a foreign key in SQL tables), called ShopId, because each product belongs to a specific Shop (I have a Parse class called Shop with an ObjectId column used in the Product Pointer.
My Product class also has a File column called imageFile that holds the image of the product.
I want to download all Products from a specific shop, unpackage their image file and put it in my Swift Product class which consists of the PFObject of the Parse Product, and a UIImageView and a UIImage. Here is my Product Class in Swift:
class Product {
private var object: PFObject
private var imageView: MMImageView!
private var image: UIImage
init(object: PFObject, image: UIImage) {
self.object = object
self.image = image
}
func getName() -> String {
if let name = object["name"] as? String {
return name
} else {
return "default"
}
}
func setImageView(size: CGFloat, target: DressingRoomViewController) {
self.imageView = MMImageView(frame:CGRectMake(0, 0, size, size))
imageView.contentMode = UIViewContentMode.ScaleAspectFit
imageView.image = self.image
imageView.setName(object["category"] as! String)
imageView.backgroundColor = UIColor.clearColor()
imageView.userInteractionEnabled = true
let tapGestureRecognizer =
UITapGestureRecognizer(target: target, action: "imageTapped:")
tapGestureRecognizer.numberOfTapsRequired = 1
imageView.addGestureRecognizer(tapGestureRecognizer)
}
func getImageView() -> MMImageView {
return self.imageView
}
}
I am currently downloading all the products just fine, and getting their image file and creating my Swift Products with their images. However my UIProgressView logic is slightly off. I have the UIProgressView running for every product, every time I unpackage the product image. I need to shift the Parse.com ProgressBlock out of the getProduct swift function and into the loadProducts #IBAction. When I try it, it causes a lot of errors before compilation. How do I shift the ProgressBlock up to the loadProducts #IBAction? Here is my current code:
//
// ChooseShopViewController.swift
// MirrorMirror
//
// Created by Ben on 12/09/15.
// Copyright (c) 2015 Amber. All rights reserved.
//
import UIKit
import Parse
class ChooseShopViewController: UIViewController {
var progressView: UIProgressView?
private var allProducts: [Product] = []
private var categories: [ProductCategory] = []
#IBAction func loadProducts(sender: AnyObject) {
let shopQuery = PFQuery(className:"Shop")
shopQuery.getObjectInBackgroundWithId("QjSbyC6k5C") {
(glamour: PFObject?, error: NSError?) -> Void in
if error == nil && glamour != nil {
let query = PFQuery(className:"Product")
query.whereKey("shopId", equalTo: glamour!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
self.getAllProductsAndCategories(objects, error: error)
}
} else {
print(error)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Create Progress View Control
progressView = UIProgressView( progressViewStyle:
UIProgressViewStyle.Default)
progressView?.center = self.view.center
view.addSubview(progressView!)
}
override func prepareForSegue( segue: UIStoryboardSegue,
sender: AnyObject?) {
if (segue.identifier == "dressingRoom") {
ShopDisplay.sharedInstance.setAllProducts(self.allProducts)
ShopDisplay.sharedInstance.setAllProductCategories(self.categories)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getAllProductsAndCategories(objects: [AnyObject]?, error: NSError?) {
if error == nil {
if let objects = objects as? [PFObject] {
for product in objects {
self.getCategory(product)
self.getProduct(product)
}
}
} else {
print("Error: \(error!) \(error!.userInfo)")
}
}
func getCategory(product: PFObject) {
if let category = product["category"] as? String {
var alreadyThere: Bool = false
for item in self.categories {
if category == item.rawValue {
alreadyThere = true
break
}
}
if alreadyThere == false {
self.categories.append(ProductCategory(rawValue: category)!)
}
}
}
func getProduct(product: PFObject) {
if let productImage = product["imageFile"] as? PFFile {
productImage.getDataInBackgroundWithBlock ({
(imageData: NSData?, error: NSError?) -> Void in
if let imageData = imageData {
let image = UIImage(data:imageData)
self.allProducts.append(
Product(object: product, image: image!))
}
if let downloadError = error {
print(downloadError.localizedDescription)
}
}, progressBlock: {
(percentDone: Int32) -> Void in
self.progressView?.progress = Float(percentDone)
if (percentDone == 100) {
//self.performSegueWithIdentifier("dressingRoom", sender: UIColor.greenColor())
}
})
}
}
}
I decided to not use the progressBlock, and instead to update my UIProgressView manually with a calculation. So here is the code. It's a little rusty. I could refactor now and maybe implement a calculated variable to make it cleaner. If my solution is a bad practice then I'm appreciative if that gets pointed out, and a better solution suggested (It doesn't seem good for performance to check the UIProgressView.progress value every iteration to perform the completion task of performing the segue).
import UIKit
import Parse
class ChooseShopViewController: UIViewController {
var progressView: UIProgressView?
private var allProducts: [Product] = []
private var categories: [ProductCategory] = []
static var numberOfProducts: Float = 0
#IBAction func loadProducts(sender: AnyObject) {
let shopQuery = PFQuery(className:"Shop")
shopQuery.getObjectInBackgroundWithId("QjSbyC6k5C") {
(glamour: PFObject?, error: NSError?) -> Void in
if error == nil && glamour != nil {
let query = PFQuery(className:"Product")
query.whereKey("shopId", equalTo: glamour!)
query.findObjectsInBackgroundWithBlock {
(objects: [AnyObject]?, error: NSError?) -> Void in
ChooseShopViewController.numberOfProducts =
Float((objects?.count)!)
print(ChooseShopViewController.numberOfProducts)
self.getAllProductsAndCategories(objects, error: error)
}
} else {
print(error)
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Create Progress View Control
progressView = UIProgressView( progressViewStyle:
UIProgressViewStyle.Default)
progressView?.center = self.view.center
progressView?.progress = 0.00
view.addSubview(progressView!)
}
override func prepareForSegue( segue: UIStoryboardSegue,
sender: AnyObject?) {
if (segue.identifier == "dressingRoom") {
ShopDisplay.sharedInstance.setAllProducts(self.allProducts)
ShopDisplay.sharedInstance.setAllProductCategories(self.categories)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func getAllProductsAndCategories(objects: [AnyObject]?, error: NSError?) {
if error == nil {
if let objects = objects as? [PFObject] {
for product in objects {
self.getCategory(product)
self.getProduct(product)
}
}
} else {
print("Error: \(error!) \(error!.userInfo)")
}
}
func getCategory(product: PFObject) {
if let category = product["category"] as? String {
var alreadyThere: Bool = false
for item in self.categories {
if category == item.rawValue {
alreadyThere = true
break
}
}
if alreadyThere == false {
self.categories.append(ProductCategory(rawValue: category)!)
}
}
}
func getProduct(product: PFObject) {
if let productImage = product["imageFile"] as? PFFile {
productImage.getDataInBackgroundWithBlock ({
(imageData: NSData?, error: NSError?) -> Void in
if let imageData = imageData {
let image = UIImage(data:imageData)
self.allProducts.append(
Product(object: product, image: image!))
self.progressView?.progress += (100.00 /
ChooseShopViewController.numberOfProducts) / 100.00
print(self.progressView?.progress)
if self.progressView?.progress == 1 {
self.performSegueWithIdentifier("dressingRoom",
sender: UIColor.greenColor())
}
}
if let downloadError = error {
print(downloadError.localizedDescription)
}
})
}
}
}
I found this on the Parse website. It may be useful as it has a block that shows the percentage done that updates regularly during the download!
let str = "Working at Parse is great!"
let data = str.dataUsingEncoding(NSUTF8StringEncoding)
let file = PFFile(name:"resume.txt", data:data)
file.saveInBackgroundWithBlock({
(succeeded: Bool, error: NSError?) -> Void in
// Handle success or failure here ...
}, progressBlock: {(percentDone: Int32) -> Void in
// Update your progress spinner here. percentDone will be between 0 and 100.
})
Did you find a better solution? besides this? I am trying to do something similar.

Swift 2.0: Could not find overload. Need Explanation

I have the following code in my program.
var detailItem: RSSItem? {
didSet {
self.configureView()
}
}
func configureView() {
if let item: RSSItem = self.detailItem
{
if let webView = self.itemWebView
{
if let templateURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("template", ofType: "html")!)?
{
if var template = NSString(contentsOfURL: templateURL, encoding: NSUTF8StringEncoding)?
{
if let title = item.title
{
template = template.stringByReplacingOccurrencesOfString("###TITLE###", withString: title)
}
if let content = item.content
{
template = template.stringByReplacingOccurrencesOfString("###CONTENT###", withString: content)
}
else if let description = item.itemDescription
{
template = template.stringByReplacingOccurrencesOfString("###CONTENT###", withString: description)
}
if let date = item.pubDate
{
var formatter = NSDateFormatter()
formatter.dateFormat = "MMM dd, yyyy"
template = template.stringByReplacingOccurrencesOfString("###DATE###", withString: formatter.stringFromDate(date))
}
if let author = item.author
{
template = template.stringByReplacingOccurrencesOfString("###AUTHOR###", withString: author)
}
webView.loadHTMLString(template, baseURL: nil)
}
}
else
{
if let content = item.content
{
webView.loadHTMLString(content, baseURL: nil)
}
else if let description = item.itemDescription
{
webView.loadHTMLString(description, baseURL: nil)
}
}
}
}
}
On the line:
if let templateURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("template", ofType: "html")!)?
I get the following error:
-Could not find an overload for 'pathForResource' that accepts the supplied arguments
Can someone explain this error to me and maybe suggest a solution. I have been reading through various searches on Google but can't quite seem to get what I need.
Thanks in advance.
NSURL(fileURLWithPath:) is now return a NSURL so just don't use if let here.
#available(iOS 2.0, *)
init(fileURLWithPath path: String, isDirectory isDir: Bool)
init(fileURLWithPath path: String) // Better to use initFileURLWithPath:isDirectory: if you know if the path is a directory vs non-directory, as it saves an i/o.
#available(iOS 2.0, *)
class func fileURLWithPath(path: String, isDirectory isDir: Bool) -> NSURL
class func fileURLWithPath(path: String) -> NSURL // Better to use fileURLWithPath:isDirectory: if you know if the path is a directory vs non-directory, as it saves an i/o.
for the line: if var template = NSString(contentsOfURL: templateURL, encoding: NSUTF8StringEncoding)?
Its decleration is:
convenience init(contentsOfURL url: NSURL, encoding enc: UInt) throws
convenience init(contentsOfFile path: String, encoding enc: UInt) throws
So it not returns optional NSString either, so you cannot use if let again. You have to use do-try-catch here.
Apple's document about this:
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html#//apple_ref/doc/uid/TP40014097-CH42-ID508
Also, you should use multiple unwrapping optional:
if let x = OptionalX, y = OptionalY { ... }
Your code is a pyramid of doom :)

Resources