Adding items to NSArrayController causes EXC_BAD_INSTRUCTION - swift

I've had the same problem for a few days now and it's been killing me. Whenever I run my script, I get a EXC_BAD_INSTRUCTION. It happens when I add an array of objects to an NSArrayController, bount to an NSTableView. Below is my code:
AppDelegate.swift:
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
#IBOutlet weak var mainTabView: NSTabView!
#IBOutlet weak var tracksAC: NSArrayController!
#IBOutlet weak var albumsAC: NSArrayController!
func checkIfFileExists(atPath path: String, isDirectory: Bool = false, createIfNeeded createNew: Bool = false) -> Int {
var isDir: ObjCBool = ObjCBool(isDirectory)
if !FileManager.default.fileExists(atPath: path, isDirectory: &isDir) {
if createNew {
do {
if isDirectory {
try FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true)
}else{
FileManager.default.createFile(atPath: path, contents: nil)
}
return 2
}catch{
return 3
}
}else{
return 0
}
}
return 1
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
//Create application support folder if it's not existent and populate with all needed files
let paths = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true)
let appSupportDir = paths[0] + "/Project Alpha"
//Create application folder if needed
let folderStatus = checkIfFileExists(atPath: appSupportDir, isDirectory: true, createIfNeeded: true)
if folderStatus == 1 || folderStatus == 2 {
_ = checkIfFileExists(atPath: appSupportDir + "/Songs.txt", createIfNeeded: true)
_ = checkIfFileExists(atPath: appSupportDir + "/Albums.txt", createIfNeeded: true)
_ = checkIfFileExists(atPath: appSupportDir + "/Genres.txt", createIfNeeded: true)
}
//Populate tracks table view
let tracks = getTracks()
print(tracks[0].name)
tracksAC.add(contentsOf: tracks) //This is where the error occures every time
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
#IBAction func openAlbumsTab(_ sender: NSToolbarItem) {
mainTabView.selectTabViewItem(at: 1)
}
}
Classes.swift:
import Cocoa
class Track: NSObject {
func getLine() -> String? {
let songsFilePath = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true)[0] + "/Project Alpha/Songs.txt"
do {
let content = try String(contentsOfFile: songsFilePath)
let lines = content.components(separatedBy: "---===---")
let line = lines.first(where: {$0.hasPrefix(String(self.identifier) + ";")})
return line
}catch{
return nil
}
}
var identifier: Int
var name: String
var artist: String
var album: String
var genre: String
var vocals: String
var trackNumber: Int
init(line: String) {
let items = line.components(separatedBy: ";")
print(items)
self.identifier = Int(items[0])!
self.name = String(items[1])
self.artist = String(items[2])
self.genre = String(items[3])
self.vocals = String(items[4])
self.album = String(items[5])
self.trackNumber = Int(items[6])!
}
}
I have checked the getTracks function and normally it does return a list of Track objects, so I really don't know what's causing the error. The columns are bound to the array controller as shown via the link below:
screenshot
Any help would be greatly appreciated. Thanks in advance.

Related

Use of unresolved identifier 'self' (CoreData)

I am using this line below :
self.present(activityViewController, animated: true, completion: nil)
And I am getting an error of - Use of unresolved identifier 'self'. Any ideas about how to resolve this? To me it looks as it it is subordinate to the class, but clearly doing something wrong. Any help would be appreciated.
import UIKit
import CoreData
class CoreDataViewController: UIViewController {
#IBOutlet weak var CoreDataView: UITableView!
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
var items:[Checkins]?
var btnnames = [""]
override func viewDidLoad() {
super.viewDidLoad()
// CoreDataView.dataSource = self
// CoreDataView.delegate = self
storeTranscription()
// Loads the current data
getTranscriptions()
// fetchCheckins()
let btn1name = btnnames[0]
let btn2name = btnnames[1]
let btn3name = btnnames[2]
let btn4name = btnnames[3]
let btn5name = btnnames[4]
let btn6name = btnnames[5]
// print(btnnames)
print(btn1name, btn2name, btn3name, btn4name, btn5name, btn6name)
}
#IBAction func export(_ sender: Any) {
exportDatabase()
}
#IBOutlet weak var Table_label: UILabel!
}
var CheckinDate: Date? = Date()
var fetchedStatsArray: [NSManagedObject] = []
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
func storeTranscription() {
//retrieve the entity that we just created
let entity = NSEntityDescription.entity(forEntityName: "Checkins", in: context)
let transc = NSManagedObject(entity: entity!, insertInto: context) as! Checkins
//set the entity values
transc.who = "Who"
transc.reason = "Reason for visit"
transc.date = CheckinDate
//save the object
do {
try context.save()
print("saved!")
} catch let error as NSError {
print("Could not save \(error), \(error.userInfo)")
} catch {
}
}
func getTranscriptions () {
//create a fetch request, telling it about the entity
let fetchRequest: NSFetchRequest<Checkins> = Checkins.fetchRequest()
do {
//go get the results
let searchResults = try context.fetch(fetchRequest)
fetchedStatsArray = searchResults as [NSManagedObject]
//I like to check the size of the returned results!
print ("num of results = \(searchResults.count)")
//You need to convert to NSManagedObject to use 'for' loops
for trans in searchResults as [NSManagedObject] {
//get the Key Value pairs (although there may be a better way to do that...
print("\(trans.value(forKey: "who")!)")
let mdate = trans.value(forKey: "CheckinDate") as! Date
print(mdate)
}
} catch {
print("Error with request: \(error)")
}
}
func exportDatabase() {
let exportString = createExportString()
saveAndExport(exportString: exportString)
}
func saveAndExport(exportString: String) {
let exportFilePath = NSTemporaryDirectory() + "Checkins.csv"
let exportFileURL = NSURL(fileURLWithPath: exportFilePath)
FileManager.default.createFile(atPath: exportFilePath, contents: NSData() as Data, attributes: nil)
//var fileHandleError: NSError? = nil
var fileHandle: FileHandle? = nil
do {
fileHandle = try FileHandle(forWritingTo: exportFileURL as URL)
} catch {
print("Error with fileHandle")
}
if fileHandle != nil {
fileHandle!.seekToEndOfFile()
let csvData = exportString.data(using: String.Encoding.utf8, allowLossyConversion: false)
fileHandle!.write(csvData!)
fileHandle!.closeFile()
let firstActivityItem = NSURL(fileURLWithPath: exportFilePath)
let activityViewController : UIActivityViewController = UIActivityViewController(
activityItems: [firstActivityItem], applicationActivities: nil)
activityViewController.excludedActivityTypes = [
UIActivity.ActivityType.assignToContact,
UIActivity.ActivityType.saveToCameraRoll,
UIActivity.ActivityType.postToFlickr,
UIActivity.ActivityType.postToVimeo,
UIActivity.ActivityType.postToTencentWeibo
]
self.present(activityViewController, animated: true, completion: nil)
}
}
func createExportString() -> String {
var checkinwho: String?
var checkinreason: String?
var export: String = NSLocalizedString("who, reason, date \n", comment: "")
for (index, itemList) in fetchedStatsArray.enumerated() {
if index <= fetchedStatsArray.count - 1 {
checkinwho = Checkins.value(forKey: "who") as! String?
checkinreason = itemList.value(forKey: "reason") as! String?
let Datevar = Checkins.value(forKey: "date") as! Date
let whostring = checkinwho
let reasonstring = checkinreason
let DateSting = "\(Datevar)"
export += "\(whostring!),\(reasonstring!),\(DateSting) \n"
}
}
print("This is what the app will export: \(export)")
return export
}
Remove the } on this line
#IBOutlet weak var Table_label: UILabel!
}
and put another } at the end of this file.

How can I reuse a variable later on in Swift

I'm trying to capture a user input (textfield + button) and reuse the result later in the program but I don't know how to do that.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var resultLabel: UILabel!
#IBOutlet weak var moneyTextField: UITextField!
#IBAction func convert(_ sender: Any) {
let convertion:Double = Double(moneyTextField.text!)!
print(convertion)
}
override func viewDidLoad() {
super.viewDidLoad()
let url = URL(string: "https://www.x-rates.com/calculator/?from=EUR&to=USD&amount=1")!
let request = NSMutableURLRequest(url : url)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
var rateValue:Double = 0.0;
if let error = error {
print(error)
} else {
if let unwrappedData = data {
let dataString = NSString(data: unwrappedData, encoding: String.Encoding.utf8.rawValue)
var stringSeperator = "<span class=\"ccOutputRslt\">"
if let contentArray = dataString?.components(separatedBy: stringSeperator){
if contentArray.count > 0 {
stringSeperator = "<span"
let newContentArray = contentArray[1].components(separatedBy: stringSeperator)
if newContentArray.count > 0 {
rateValue = Double(newContentArray[0])!
print(newContentArray[0])
}
}
}
}
}
//
print("Rate is \(rateValue)");
DispatchQueue.main.sync(execute: {
self.resultLabel.text = "the value of the dollar is " + String(rateValue)
}
)}
task.resume()
}
}
What I want to do is take the let convertion and multiply it by rateValue at the end of the code. I tried different thing but without any results.
after the advice from Joakim Danielson
I did that :
import UIKit
class ViewController: UIViewController {
var fxRate: Double?
#IBOutlet weak var resultLabel: UILabel!
#IBOutlet weak var moneyTextField: UITextField!
#IBAction func convert(_ sender: Any) {
let convertion:Double = Double(moneyTextField.text!)!
print(convertion)
var convertedAmount = 0.0
if let rate = fxRate, let money = Double(moneyTextField.text) {
convertedAmount = rate * money
}
print(convertedAmount)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let url = URL(string: "https://www.x-rates.com/calculator/?from=EUR&to=USD&amount=1")!
let request = NSMutableURLRequest(url : url)
let task = URLSession.shared.dataTask(with: request as URLRequest) {
data, response, error in
var rateValue:Double = 0.0;
if let error = error {
print(error)
} else {
if let unwrappedData = data {
let dataString = NSString(data: unwrappedData, encoding: String.Encoding.utf8.rawValue)
var stringSeperator = "<span class=\"ccOutputRslt\">"
if let contentArray = dataString?.components(separatedBy: stringSeperator){
if contentArray.count > 0 {
stringSeperator = "<span"
let newContentArray = contentArray[1].components(separatedBy: stringSeperator)
if newContentArray.count > 0 {
rateValue = Double(newContentArray[0])!
print(newContentArray[0])
rateValue = Double(newContentArray[0])!
self.fxRate = rateValue
}
}
}
}
}
//
print("Rate is \(rateValue)");
DispatchQueue.main.sync(execute: {
self.resultLabel.text = "the value of the dollar is " + String(rateValue)
}
)}
task.resume()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
but I have the error : Cannot invoke initializer for type 'Double' with an argument list of type '(String?)' on line 26. Can you please help me? thx!
create a variable outside of your function
var anyVariableYouWantToAccessLater: Double?
And use this variable anywhere you want.
Since you're downloading the rate during viewDidLoad I am assuming this is what you want to keep.
Add a new property to the class
class ViewController: UIViewController {
var fxRate: Double?
...
In viewDidLoad update this property with the downloaded value
rateValue = Double(newContentArray[0])!
fxRate = rateValue
In the convert func (or wherever you want to use the rate)
#IBAction func convert(_ sender: Any) {
var convertedAmount = 0.0
if let rate = fxRate, let money = Double(moneyTextField.text ?? "0") {
convertedAmount = rate * money
}
print(convertedAmount)
}

Retrieving image from firebase? (swift)

So i have a firebase structure like the pic below
Now i want to retrieve that image file that i've uploaded. to decode the base64String and show it. Every user can make a post and the information that will be sended to firebase has a description etc. and also have an image. now i tried to retrieve it whit this codes but nothing did work.
var REF_LIST = Firebase(url: "\(URL_BASE)/listItems")
REF_LIST.observeEventType(FEventType.Value, withBlock: { snapshot in
let image = snapshot.value.objectForKey("images") as! String
but this already gave me a nil error on that line, so i couldn't even decode. i think i understand why it's giving me a nil error, there is no images in listItems on firebase, you first have the unique ID and then the specs with images in. now i don't now how i can retrieve that information from that unique ID?
UPDATE:
the tableViewController what will receive the data from firebase:
import UIKit
import FBSDKLoginKit
import Alamofire
import Firebase
class ListVC: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var lists = [List]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
dispatch_async(backgroundQueue, {
self.initObservers()
})
}
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.tableView.reloadData()
}
func initObservers() {
LoadingOverlay.shared.showOverlay(self.view)
DataService.ds.REF_LISTS.observeEventType(.Value, withBlock: { snapshot in
print(snapshot.value)
self.lists = []
if let snapshots = snapshot.children.allObjects as? [FDataSnapshot] {
for snap in snapshots {
print("SNAP: \(snap)")
if let listDict = snap.value as? Dictionary<String, AnyObject> {
let key = snap.key
let list = List(listKey: key, dictionary: listDict)
self.lists.insert(list, atIndex:0)
}
}
}
self.tableView.reloadData()
LoadingOverlay.shared.hideOverlayView()
})
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return lists.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier("ListCell") as? ListCell {
let list = self.lists[indexPath.row]
cell.request?.cancel()
cell.configureCell(list)
return cell
} else {
return ListCell()
}
}
}
the addController which post the data to firebase:
import UIKit
import Firebase
import Alamofire
import FBSDKCoreKit
class AddVC: UIViewController, UITextFieldDelegate, UITextViewDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
#IBOutlet weak var addTitle: UITextField!
#IBOutlet weak var addDescription: UITextView!
#IBOutlet weak var addLocation: UITextField!
#IBOutlet weak var placeholderLbl: UILabel!
#IBOutlet weak var freeSwitch: UISwitch!
#IBOutlet weak var tradeSwitch: UISwitch!
#IBOutlet weak var imageSelectorImg: UIImageView!
#IBOutlet weak var overlayView: UIView!
var currentUsername = ""
var imageSelected = false
var imagePicker: UIImagePickerController!
var base64String: NSString = ""
override func viewDidLoad() {
super.viewDidLoad()
addTitle.delegate = self
addDescription.delegate = self
addLocation.delegate = self
imagePicker = UIImagePickerController()
imagePicker.delegate = self
getCurrentUser()
hideKeyboardWhenTappedAround()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
addTitle.text = ""
addDescription.text = ""
addLocation.text = ""
freeSwitch.setOn(false, animated: false)
tradeSwitch.setOn(false, animated: false)
placeholderLbl.hidden = false
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getCurrentUser() {
DataService.ds.REF_USER_CURRENT.observeEventType(FEventType.Value, withBlock: { snapshot in
let currentUser = snapshot.value.objectForKey("username") as! String
print("Username: \(currentUser)")
self.currentUsername = currentUser }, withCancelBlock: { error in
print(error.description)
})
}
func imagePickerController(picker: UIImagePickerController, didFinishPickingImage image: UIImage, editingInfo: [String : AnyObject]?) {
imagePicker.dismissViewControllerAnimated(true, completion: nil)
imageSelectorImg.image = image
dispatch_async(backgroundQueue, {
let uploadImage = image
let imageData = UIImageJPEGRepresentation(uploadImage, 0.5)
self.base64String = imageData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
})
imageSelected = true
}
#IBAction func selectImage(sender: UITapGestureRecognizer) {
presentViewController(imagePicker, animated: true, completion: nil)
}
func postToFirebase() {
// LoadingOverlay.shared.showOverlay(self.overlayView)
var post: Dictionary<String, AnyObject> = ["username": self.currentUsername, "description": self.addDescription.text!, "title": self.addTitle.text!, "location": self.addLocation.text!, "images": self.base64String]
if self.freeSwitch.on && self.tradeSwitch.on {
post["tradeOption"] = "Gratis/Te ruil"
} else if self.freeSwitch.on {
post["tradeOption"] = "Gratis"
} else if self.tradeSwitch.on {
post["tradeOption"] = "Te ruil"
}
let firebasePost = DataService.ds.REF_LISTS.childByAutoId()
firebasePost.setValue(post)
}
#IBAction func postListItem(sender: AnyObject) {
if let addTitle = addTitle.text where addTitle != "", let addDescription = addDescription.text where addDescription != "", let addLocation = addLocation.text where addLocation != "" {
dispatch_async(backgroundQueue, {
self.postToFirebase()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let listVC = storyboard.instantiateViewControllerWithIdentifier("TBC") as! UITabBarController
listVC.selectedIndex = 1
self.presentViewController(listVC, animated: false, completion: nil)
})
})
}
}
func textViewDidBeginEditing(textView: UITextView) {
placeholderLbl.hidden = true
}
func textViewDidEndEditing(textView: UITextView) {
if textView.text == "" {
placeholderLbl.hidden = false
}
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
}
and the swift file to configure the cell:
import UIKit
import Alamofire
import Firebase
class ListCell: UITableViewCell {
#IBOutlet weak var listImg: UIImageView!
#IBOutlet weak var listTitle: UILabel!
#IBOutlet weak var listTradeOption: UILabel!
#IBOutlet weak var listLocation: UILabel!
#IBOutlet weak var headImg: UIImageView!
var list: List!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
func retrieveImages() {
DataService.ds.REF_LISTS.observeEventType(FEventType.Value, withBlock: { snapshot in
if let snapshots = snapshot.children.allObjects as? [FDataSnapshot] {
for snap in snapshots {
let image = snap.value.objectForKey("images") as! String
let decodedData = NSData(base64EncodedString: image, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
let decodedImage = UIImage(data: decodedData!)
self.headImg.image = decodedImage
}
}
})
}
func configureCell(list: List) {
self.list = list
self.listTitle.text = list.listTitle
self.listTradeOption.text = list.listTradeOption
self.listLocation.text = list.listLocation
retrieveImages()
}
}
also the list Model file:
import Foundation
import Firebase
class List {
private var _listTitle: String!
private var _listDescription: String!
private var _listTradeOption: String!
private var _listLocation: String!
private var _listImageURL: String?
private var _listKey: String!
private var _listRef: Firebase!
var listTitle: String? {
return _listTitle
}
var listDescription: String? {
return _listDescription
}
var listTradeOption: String? {
return _listTradeOption
}
var listLocation: String? {
return _listLocation
}
var listKey: String {
return _listKey
}
var listImageURL: String? {
return _listImageURL
}
init(title: String, description: String, tradeOption: String, location: String, listImageURL: String?) {
self._listTitle = title
self._listDescription = description
self._listTradeOption = tradeOption
self._listLocation = location
self._listImageURL = listImageURL
}
init(listKey: String, dictionary: Dictionary<String, AnyObject>) {
self._listKey = listKey
if let title = dictionary ["title"] as? String {
self._listTitle = title
}
if let desc = dictionary ["description"] as? String {
self._listDescription = desc
}
if let trade = dictionary ["tradeOption"] as? String {
self._listTradeOption = trade
}
if let loc = dictionary ["location"] as? String {
self._listLocation = loc
}
if let imgUrl = dictionary["images"] as? String {
self._listImageURL = imgUrl
}
self._listRef = DataService.ds.REF_LISTS.childByAppendingPath(self._listKey)
}
}
i've got also a DataServicefile, where i create a user by unique ID with this code:
var REF_USER_CURRENT: Firebase {
let uid = NSUserDefaults.standardUserDefaults().valueForKey(KEY_UID) as! String
let user = Firebase(url: "\(REF_BASE)").childByAppendingPath("users").childByAppendingPath(uid)
return user!
}
func createFirebaseUser(uid: String, user: Dictionary<String, String>) {
REF_USERS.childByAppendingPath(uid).setValue(user)
}
i know it's a lot but maybe the best way to help :)
Try editing this in List Cell
var imageURL = String()
func retrieveImages() {
let decodedData = NSData(base64EncodedString: imageURL, options: NSDataBase64DecodingOptions.IgnoreUnknownCharacters)
let decodedImage = UIImage(data: decodedData!)
self.headImg.image = decodedImage
}
func configureCell(list: List) {
self.list = list
self.listTitle.text = list.listTitle
self.listTradeOption.text = list.listTradeOption
self.listLocation.text = list.listLocation
self.imageURL = list.listImageURL //you already had the image url for that specific cell
retrieveImages()
}
Storing and accessing images using base64String in firebase is not an
efficient way, instead of that we can use FirebaseStorage (Google cloud storage
bucket) for uploading images to Firebase and it will provide us
download URL for a particular image. We can store that URL into our database simply in a string format and access it whenever we
required and then download the corresponding image from that URL by
using SDWebImage.
Refer below link for integrating FirebaseStorage into your project: https://firebase.google.com/docs/storage/ios/upload-files

Saving highscores with NSUserDefaults

I'm trying to save the highscore of my game. I'm trying to do this via NSUserDefaults. This is the code I'm using:
//To save highest score
var highestScore:Int = 20
NSUserDefaults.standardUserDefaults().setObject(highestScore, forKey:"HighestScore")
NSUserDefaults.standardUserDefaults().synchronize()
//To get the saved score
var savedScore: Int = NSUserDefaults.standardUserDefaults().objectForKey("HighestScore") as Int
println(savedScore)
But I get an error with NSUserDefaults saying "Expected declaration" and I can't figure out how to properly implement this.
Or should I be using NSArchiver for this? And if that is the case how could I implement this?
Use NSCoding. Create a Swift file "HighScore"
import Foundation
class HighScore: NSObject {
var highScore: Int = 0
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeInteger(highScore, forKey: "highScore")
}
init(coder aDecoder: NSCoder!) {
highScore = aDecoder.decodeIntegerForKey("highScore")
}
override init() {
}
}
class SaveHighScore:NSObject {
var documentDirectories:NSArray = []
var documentDirectory:String = ""
var path:String = ""
func ArchiveHighScore(#highScore: HighScore) {
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("highScore.archive")
if NSKeyedArchiver.archiveRootObject(highScore, toFile: path) {
println("Success writing to file!")
} else {
println("Unable to write to file!")
}
}
func RetrieveHighScore() -> NSObject {
var dataToRetrieve = HighScore()
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("highScore.archive")
if let dataToRetrieve2 = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? HighScore {
dataToRetrieve = dataToRetrieve2
}
return(dataToRetrieve)
}
}
Then for your ViewController:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
var Score = HighScore()
override func viewDidLoad() {
super.viewDidLoad()
Score.highScore = 100
SaveHighScore().ArchiveHighScore(highScore: Score)
var retrievedHighScore = SaveHighScore().RetrieveHighScore() as HighScore
println(retrievedHighScore.highScore)
}
}

Unable to decode a NSObject in Swift

I am having a problem decoding an object after I encode it in Swift.
Here is my class:
class Player: NSObject, NSCoding {
var score:Int = 0
init(difficulty: Int!) {
super.init()
}
required init(coder aDecoder: NSCoder) {
score = aDecoder.decodeObjectForKey("score") as Int
}
func encodeWithCoder(aCoder: NSCoder) {
aCoder.encodeObject(score, forKey: "score")
}
Here is when I am encoding and decoding:
let data = NSKeyedArchiver.archivedDataWithRootObject(player)
let newPlayer = NSKeyedUnarchiver.unarchiveObjectWithData(data) as Player
It crashes everytime when I try to unarchive it. Anybody have any reasons why?
P.S. I have no idea why my code isn't formatted. I have it indented 4 spaces over! Sorry about that!
Here is what I did to get it working:
Created an instance of player in my App Delegate
You can call this anywhere if your application UIApplication.sharedApplication().player
For storing arrays of Player objects here are the NSObject classes:
import Foundation
class Player: NSObject {
var score:Int = 0
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeInteger(score, forKey: "score")
}
init(coder aDecoder: NSCoder!) {
score = aDecoder.decodeIntegerForKey("score")
}
override init() {
}
}
class ArchivePlayer:NSObject {
var documentDirectories:NSArray = []
var documentDirectory:String = ""
var path:String = ""
func savePlayerArray(#playerArray: [Player]) {
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("playersArray.archive")
if NSKeyedArchiver.archiveRootObject(playerArray, toFile: path) {
println("Success writing to file!")
} else {
println("Unable to write to file!")
}
}
func retrievePlayerArray() -> NSObject {
var dataToRetrieve = [Player]()
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("playersArray.archive")
if let dataToRetrieve2 = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? [Player] {
dataToRetrieve = dataToRetrieve2
}
return(dataToRetrieve)
}
}
Here is the ViewController:
import UIKit
class ViewController: UIViewController {
var player1 = Player()
var player2 = Player()
var player3 = Player()
var playerArchiveArray = [Player]()
override func viewDidLoad() {
super.viewDidLoad()
player1.score = 12
player2.score = 22
player3.score = 32
playerArchiveArray = [player1, player2, player3]
ArchivePlayer().savePlayerArray(playerArray: playerArchiveArray)
var playerRetrieveArray = ArchivePlayer().retrievePlayerArray() as [Player]
for player in playerRetrieveArray {
println(player.score)
}
}
}
This should work. I will post a separate answer if you wish to save an array of Player objects.
Two NSObject classes:
import Foundation
class Player: NSObject {
var score:Int = 0
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeInteger(score, forKey: "score")
}
init(coder aDecoder: NSCoder!) {
score = aDecoder.decodeIntegerForKey("score")
}
override init() {
}
}
class ArchivePlayer:NSObject {
var documentDirectories:NSArray = []
var documentDirectory:String = ""
var path:String = ""
func savePlayer(#player: Player) {
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("players.archive")
if NSKeyedArchiver.archiveRootObject(player, toFile: path) {
println("Success writing to file!")
} else {
println("Unable to write to file!")
}
}
func retrievePlayer() -> NSObject {
var dataToRetrieve = Player()
documentDirectories = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
documentDirectory = documentDirectories.objectAtIndex(0) as String
path = documentDirectory.stringByAppendingPathComponent("players.archive")
if let dataToRetrieve2 = NSKeyedUnarchiver.unarchiveObjectWithFile(path) as? Player {
dataToRetrieve = dataToRetrieve2 as Player
}
return(dataToRetrieve)
}
}
And then in the ViewController:
import UIKit
class ViewController: UIViewController {
var player = Player()
override func viewDidLoad() {
super.viewDidLoad()
player.score = 22
ArchivePlayer().savePlayer(player: player)
let playerToRetrieve = ArchivePlayer().retrievePlayer() as Player
println(playerToRetrieve.score)
}
}
This demonstrates archiving and unarchiving to file. Printing "Success writing to file!" to demonstrate the archiving. Printing the stored object player.score to demonstrate unarchiving.