SpriteKit in screensaver can't find images - swift

I am making a screensaver in Swift using SpriteKit.
While testing screensaver in app, all the textures load properly. As soon as I make .saver and load it in System Preferences, SpriteKit shows that images are not found.
I used (imageNamed: ""), so I tried using
var imageURL = Bundle.main.url(forResource: "gradient", withExtension: "png")
let imageGradient = NSImage(contentsOf: imageURL!)!
,but I got the same result.
SpriteKit can't access images when built into .saver file, but works perfectly when ran through the app.
I have included images in bundle, in assets, in Target's Copy Bundle Resources/Development Assets/Resource Tags.
You can clone the project from here: https://github.com/Nazar-Bibik/SavePortal

I have looked into this project: https://github.com/leebradley/nyan-screensaver
And I found how to properly do it:
You need to put images into bundle, not xcassets ( put it with .swift files )
Instead of using image name use the following
let sourceBundle = Bundle(for: MainSwiftFile.self)
let imagePath = sourceBundle.path(forResource: "picture-name", ofType: "png")!
neededTextures = SKTexture(imageNamed: imagePath)
You need to provide the name of the .swift file with your principal class ( principle class in info.plist file ).
The rest is simple - forResource is a file name, ofType is a file extension and instead of passing usual name in imageNamed: you provide String of path to file.
"imagePath" is of a String type.

Related

importing obj (or dae or lidar scan ) into swift SceneAssests without using xcode gui interface from files during app runtime

System. (Mac OS:Catalina 10.15.7 ,xcode version: 12.3 , swift language version 5)
Has anyone accessed a .dae or .obj in the project file ( in files ) on an ipad/iphone and been able to create a sceneAsset from this file? I do not want to use the graphical interface in xcode and drop files in before the app builds. I want to be able to load and create a scene (.scn) with the image overlay and use whatever object origin that was in the file as the new scene origin. Is this even possible?
I have been playing with some example code with modelIO but hasn't really worked yet.
ex. Call the function somewhere and tell it the filename "scannedChair"
below is from https://developer.apple.com/forums/thread/103245
func loadSavedOBJ(filename:String)->Project?{
let DocumentDirectoryURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let objURL = DocumentDirectoryURL.appendingPathComponent(filename).appendingPathExtension("exampleProject")
//return loadProject(url: fileURL)
let asset = MDLAsset(url:objURL)
guard let object = asset.object(at: 0) as? MDLMesh else {
fatalError("Failed to get mesh from obj asset.")
}
// Wrap the ModelIO object in a SceneKit object
let scene = SCNScene()
let node = SCNNode(mdlObject: object)
scene.rootNode.addChildNode(node)
everywhere i try to search for this people are so focused on exporting 3d files from their app or using them in augmented reality but not so much to use scanned items in a traditional app scene. ex. I scan a chair and want that chair to be seen in a pov game or app.
*note: I am very green in xcode / swift . I'm just looking for pointers at not a solution unless it presents itself. Apologies if my terminology is completely off-base.

Xcode. Image resources added to a test target are not copied into the tests bundle

I wrote some extension to UIImage class and want to cover it by Unit Tests. I added some image to test target and checked that it presents in the Copy Bundle Resources list.
In the test code I use a model object which pvovides me test data.
class TestConstants {
private static var bundle: Bundle {
return Bundle(for: UIImageExtensionsTests.self)
}
private static var birdImageURL: URL {
let path = self.bundle.url(forResource: "birds", withExtension: "png")
return path!
}
static var birdImageData: Data {
return try! Data(contentsOf: self.birdImageURL)
}
}
Unfortunately birds.png image is not located in test bundle, but another resource drm.txt presents.
I'm a bit confused is it the bug in Xcode?
By the way I downloaded Xcode 9.4 beta and there are the same behavior - images do not copy into the test bundle.
#UPDATE:
UIImageExtensionsTests is a test class presents in the same target with drm.txt and birds.png file
To get the appropriate Bundle use :
let bundle = Bundle.init(for: TestConstants.classForCoder())
My bad that I didn't read log carefully.
The issue was happen with "wrong" image founded in internet. Xcode couldn't proceed image, so it didn't copy it to test bundle.
While reading
/Users/igork/developer/gitlab/ios.gym-master/GymMasterTests/Resources/birds.png
pngcrush caught libpng error: Not a PNG file..
And this error doesn't fail building and running the target. So in my case the tests were starting :(

Read a file in a macOS Command Line Tool project

I've added a few JSON files to my macOS Command Line Tool project, but I can't seem to find them the usual way.
if let path = Bundle.main.path(forResource: "Data", ofType: "json")
{
if let contents = try? String(contentsOfFile: path)
{
print (contents)
}
else { print("Could not load contents of file") }
}
else { print("Could not find path") }
This code works absolutely fine when used in a View based application, but always prints "Could not find path" in the command line tool.
Does anyone know what I'm doing wrong?
P.S: Fully aware that I should be using guard statements for this, but the code isn't in a function, just faffing about in main.swift till I figure this out.
You can create a separate bundle, place the files there, and then load them without having to worry about their individual URLs.
Let's do it:
In Xcode, click on File --> New --> Target...
Click on the macOS tab at the top
Scroll down to the Framework & Library, select Bundle, click Next. Give a name to the new bundle (let's say JSONMocks).
Add files to this bundle. Add the file to Xcode, then make sure that the bundle is ticked in its target membership section:
Add the bundle to your target. In the target's Build Phases, open the Copy Files phase and click the + button. Select the bundle and click Add:
Programmatically access the contents of your bundle thus:
let currentDirectoryURL = URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
let bundleURL = URL(fileURLWithPath: "JSONMocks.bundle", relativeTo: currentDirectoryURL)
let bundle = Bundle(url: bundleURL)
let jsonFileURL = bundle!.url(forResource: jsonFileName, withExtension: "json")!
There is no app bundle for a command-line tool. Just a binary.
You need to put the JSON file in a known location (current directory?) and construct the path yourself

Get number of images in xcasset

I want to programmatically load a couple of images into arrays from my xcassets. I don't know how many images there are in the asset, but the images are named in order, like this: "img1_1", "img1_2", "img2_1", "img2_2", ...
I put the images in folders inside the asset, so folder "images1" contains all images with names starting with "img1_" and the folder called "images2" contains all images starting with "img2_". Does that help?
How do I get the number of images in the asset that are named like that so I can iterate through them and add them to my array?
There isn't a real easy way to go about it since the files are placed in the app at compile time. You can, though, create a RunScript in the Build Phases to be ran before compiling that creates a text file of the images. Then you can read in that text file and populate an array of images. You can use that array to get the details you need.
RunScript in the Build Phases:
#!/bin/sh
>./your_app_folder/fileNames.txt
for FILE in ./your_app_folder/Images.xcassets/actions/*; do
echo $FILE >> ./your_app_folder/fileNames.txt
done
Also, here's a link to an accepted answer that a previous poster asked with more details.
Another option if you do not want to deal with Build Phases, and one I'd probably choose, is not to use the Assets.xcassets file. Just place the images in a folder within your app bundle. It's much easier to read from the bundle.
UPDATE:
For the second option, you can drag your images (or folder of images) to your project, but be sure copy as a folder reference rather than group. Then in your code, you can read that folder using the FileManager.
let fileManager = FileManager.default
let imagePath = Bundle.main.resourcePath! + "/your_new_folder"
let imageNames = try! fileManager.contentsOfDirectory(atPath: imagePath)
imageNames in this case will be an array of file names within that url path. If go this route, you probably have to load the images by contentsOfFile too.
if let imagePath = bundle.path(forResource: fileName, ofType: nil) {
myImage = UIImage(contentsOfFile: imagePath)
}

NSBundle.mainBundle().URLForResource("bach1", withExtension: "jpg") returning null

NSBundle.mainBundle().URLForResource("bach1", withExtension: "jpg")
The above code is returning null.
In order to check if the file exists or not, I used below code:
let fileManager = NSFileManager.defaultManager()
if fileManager.fileExistsAtPath(savepath) {
println("exist")
}
The above code returns that file exists in directory.
So I don't understand why the first code is returning null
Your problem is that NSBundle.mainBundle().URLForResource("bach1", withExtension: "jpg") returns an optional NSURL. You need to use if let to unwrap it and extract your file path from the returned url as follow:
if let resourceUrl = NSBundle.mainBundle().URLForResource("bach1", withExtension: "jpg") {
if NSFileManager.defaultManager().fileExistsAtPath(resourceUrl.path!) {
print("file found")
}
}
Swift 3.x
if let resourceUrl = Bundle.main.url(forResource: "bach1", withExtension: "jpg") {
if FileManager.default.fileExists(atPath: resourceUrl.path) {
print("file found")
}
}
I found that you have to actually go into Build Phases -> Copy Bundle Resources and manually add your item sometimes to the bundle. In my case it was a video file that didn't get added to the bundle correctly on its own.
NSBundle.URLForResource only returns files that are bundled in your application at build/compile time, like when you drag a file into your Xcode project and add it to your app target. You can typically use this when your app comes preloaded with resources you need, like images, movies, databases, and other files.
It seems like savepath is a path your application wrote to while running (maybe into your app's Documents directory?). Because of this, the file is outside of the bundle and you will need to store that path/URL somewhere (or build it up again) if you need to reference the file in the future.
I had this issue too. My fix was:
Selecting the file in project navigator
Open the 'File Inspector' (on the right hand side pane)
Checking the app target in the Target Membership