scnScene.write not writing the scene to .scn file - swift

I am working on a project in SceneKit that the user could change the object in the scene and want to be able to save the state of the scene when the user hit the submit button. In the documentation for SceneKit, there is a function call write: https://developer.apple.com/documentation/scenekit/scnscene/1523577-write. However, when I used it following the instruction, it doesn't write to the file. I also used the file scheme like they said in the documentation to create the URL: https://developer.apple.com/documentation/foundation/url.
Here is my code. Thank you for all your help. This is very new to me so any more advice would be much appreciated.
#IBAction func submitButton(_ sender: UIButton) {
let scnurl = NSURL.fileURL(withPath: "State.scn")
if(scnScene.write(to: scnurl, options: nil, delegate: nil, progressHandler: nil)){
print("tis success")
}
print("This button work")
}
The button does work because it prints out "This button work" but it doesn't print out "tis success" because the function return false.

I'd make use of the last parameter of the SCNScene.write() method, there's a progress handler there can will potentially give you an error with information if it fails.
I expect it's failing because of the URL you're giving it. Take a look at getting a URL from FileManager and append your filename to that.

Related

Text label not updating on screen, even though it shows up on `print()`

I'm writing an application which has an NSSplitViewController as the main View-Controller. I have it linked-up so that clicking a button in the menubar will trigger an #IBAction which then calls a function in one of the sub-View-Controllers.
if let board = storyboard {
let imageController = board.instantiateController(withIdentifier: "VC_image_ID") as! VC_image
imageController.viewDidAppear() // necessary or else I'll get an "Unexpectedly found nil" later on
DispatchQueue.global().async{imageController.processImage(path)} // path variable was set earlier in the code, but not shown here
}
Inside the sub-View-Controller (named VC_image), I'm trying to change the stringValue of a label by using the following code:
public func processImage(_ path: String) {
DispatchQueue.main.async {
self.imageText.stringValue = path
print(self.imageText.stringValue)
}
}
Although the imageText.stringValue actually seems to have changed based on the fact that it prints the updated text (through the console), the text in the window never changes. Why is this happening? The reason is probably really obvious to professionals, but I'm still an amateur and can't figure it out. Thanks.

NSSavePanel name not user editable

I'm a total beginner to OSX GUI programming, so please be gentle with me.
I'm trying some experiments with adding light GUI elements from appkit to a CLI, so I'm working on a very small program to take the contents of a PDF and save it to a text file.
Here's the code I have
import AppKit
import Foundation
import Quartz
func helperReadPDF(_ filename: String) -> String {
let pdata = try! NSData(contentsOfFile: filename) as Data
let pdf = PDFDocument(data: pdata)
return pdf!.string!
}
func selectFile() -> URL? {
let dialog = NSOpenPanel()
dialog.allowedFileTypes = ["pdf"]
guard dialog.runModal() == .OK else { return nil }
return dialog.url
}
func getSaveLocation() -> URL? {
let sa = NSSavePanel()
sa.nameFieldStringValue = "Untitled.txt"
sa.canCreateDirectories = true
sa.allowedFileTypes = ["txt"]
guard sa.runModal() == .OK else { return nil }
return sa.url
}
let file = selectFile()?.path ?? ""
print("where to save?")
let dest = getSaveLocation()!
try! helperReadPDF(file).write(to: dest, atomically: true, encoding: .utf8)
(I know, there are lots of unidiomatic things in here, like all the forced unwrapping and pointlessly converting URLs to paths. I have obscure reasons...)
So this code mostly works: when I run it from a terminal window with swift guitest.swift it'll pop up a file picker window, let me select a pdf file, and then pop up a save dialogue and let me choose the directory, and then save the extracted text from the pdf into that directory.
But it won't let me change the filename. I can highlight the "Untitled.txt" provided by default, I can even get a cursor into the field... but it doesn't respond to keyboard input.
In this previous SO, someone suggested adding a nameFieldStringValue to make it editable, but, as you can see from the above code, I did that, and it doesn't work.
I see from this very old SO that at least in Objective-C-land, you have to initiate some kind of application object in order to accept keyboard input. Is that true today in Swift-land as well?
(Even though for some weird reason you can accept mouse input without doing any of that?!) If so, how do I do that here?
Edit: I get from the comments to that last prior SO I linked that this is probably a terrible idea, and that if I want to learn Mac GUI programming I should do it the heavy way with XCode and storyboards and all the rest. But could you indulge my doing it the stupid way in an effort to try to learn one thing at a time? (I.e., learn the GUI APIs on offer without also trying to learn XCode and Apple's preferred style of architecture at the same time.)
Thanks!
(Swift 4.2 on latest version of OSX. Not using XCode at all.)
Setting the application's ActivationPolicy will make it work.
// Import statements... (import Quartz)
NSApplication.shared.setActivationPolicy(.accessory)
// Functions and so on... (func helper..)

How to correctly unset an array from UserDefaults in Swift

I am new to swift and learning about UserDefaults. When a user logs into my application, I am storing a key to check if he is 'logged in' and I unset this key every time the user logs out.
I save it and unset it as:
UserDefaults.standard.set(true, forKey: "isUserLoggedIn");
UserDefaults.standard.set(false, forKey: "isUserLoggedIn");
I also save an array with the user's details. I want to know how I can unset this when the log out button is pressed?
The code for saving the details is:
let array = [storedUsername, storedFirstname, storedSurname, storedUniName, storedUniCourse, storedEmail];
UserDefaults.standard.set(array, forKey: "UserDetailsArray");
UserDefaults.standard.synchronize();
I have tried to remove them by:
UserDefaults.standard.removeObject(forKey: "UserDetailsArray")
But this doesn't work, so I wanted to know what is the correct way for doing this? Thank you!
EDIT
This is the complete function I call when logging out. The objective is to remove the array of the users details + also to set UserLoggedIn to false
#IBAction func LogoutButtonTapped(_ sender: Any) {
UserDefaults.standard.set(false, forKey: "isUserLoggedIn");
UserDefaults.standard.removeObject(forKey: "UserDetailsArray")
UserDefaults.standard.synchronize();
self.performSegue(withIdentifier: "LoginViewController", sender: self);
}
There seemed to be a bug somewhere maybe because I was setting UserDefaults for the first time? I'm not sure. Anywhere I included this snippet before I save anything and removed it after running it once in the code:
if let bundle = Bundle.main.bundleIdentifier {
UserDefaults.standard.removePersistentDomain(forName: bundle)
}
It seemed to do the trick! The information saves and retrieves perfectly now

Unit testing for IBAction connection with good form

I've created a successful unit test that checks for an IBAction in Swift. However, the form isn't great:
func testAddButtonIBActionShouldExist() {
let actions=viewController.addButton.actionsForTarget(viewController, forControlEvent: UIControlEvents.TouchUpInside)
XCTAssertNotNil(actions, "Add button should have conections")
if actions != nil{
let actionsAsNSArray:NSArray=actions! as NSArray
XCTAssertTrue(actionsAsNSArray.containsObject("addNumbers:"), "Add button not connected to correct IBAction")
}
}
It separates the test for nil and the containsObject into two separate parts, and also includes an if… both of which I believe are bad unit testing form. Is there a way to somehow combine these in Swift 1.2 (or Swift 2)? Thanks for reading.

Add player score to social framework message in SpriteKit

I'm making a SpriteKit based-app, and I have a spriteNode that shares to facebook when I tap it. This is the code that runs when it is tapped:
func shareToFacebook(){
var shareToFacebook: SLComposeViewController = SLComposeViewController(forServiceType: SLServiceTypeFacebook)
shareToFacebook.setInitialText("I just got x points in ....")
shareToFacebook.addImage(UIImage(named: "AppLogo87.png"))
let vc: UIViewController = self.view!.window!.rootViewController!
vc.presentViewController(shareToFacebook, animated: true, completion: nil)
}
I also have a score system set up within the game. What I want to do is display the score in the setInitialText message. I want it to say "I just got ___ points in app". I can't figure out how to add the player's score to the message.
I've read this twice and feel like I'm missing something, however if you are really just asking how to include a variable in text output then:
var scoreVar = object.getPoints()
var appName = object.getAppName()
shareToFacebook.setInitialText("I just got \(scoreVar) points in \(appName)")
If you're asking something else, then you'll have to be clearer (at least for me!).