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

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 :(

Related

SpriteKit in screensaver can't find images

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.

Swift Default Overload Unavailable - SCNReferenceNode(named: ) is not found

I am relatively new to Xcode.
Wondering how two files, with identical code can yield two very different build results. The first is downloaded from Apple's "Creating Face Based AR Experiences" sample code and the second is an implementation for my project. I've tried everything I can think of; rebuilding, cleaning, reinstalling, rebooting.... Even copied the exact code over from Apple's sample (as shown) and still fails. Seems to be an error that is keeping SCNReferenceNode from working properly in my project (to the right). Both files were working perfectly earlier. I have tried replacing code with SCNReferenceNode(url: ) combined with Bundle.main.url(forResource: withExtension: ) and displays the same error. It could be related; when loading project there seemed to be some missing documents (highlighted in red in Xcode) although they are in the physical files themselves. I have included a screenshot of the side by side comparison; as you can see, identical yet still an error. Any ideas on what could be causing this?
Screenshot:
If you take a look in the Utilites.swift file Apple have added an extension to SCNReferenceNode that adds a convenience init function.
extension SCNReferenceNode {
convenience init(named resourceName: String, loadImmediately: Bool = true) {
let url = Bundle.main.url(forResource: resourceName, withExtension: "scn", subdirectory: "Models.scnassets")!
self.init(url: url)!
if loadImmediately {
self.load()
}
}
}

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

Xcode Project Folder Structure

I am using the latest XCode / Swift 3.0 and facing some problems:
I created a folder in /MyProject/MyProject/Assets/Subfolder1 and stored a few hundred .txt files in it to iterate over the files inside the Subfolder1 with the following code:
let fm = FileManager.default
fm.enumerator(atPath: "/MyProject/Assets/Subfolder1")?.forEach({ (e) in
if let e = e as? String, let url = URL(string: e) {
doSomethingWith(url.pathExtension)
}
})
But I cannot find any files. I tried some variations ("/Assets/Subfolder1/" and "/MyProject/MyProject/Assets/Subfolder1"), all are not working.
What is the correct path that I have to specify?
Best
Chris
First off, make sure you have added the actual folder to the Xcode project. You can do this simply by dragging and dropping the folder into your project. After you drag and drop, this window should appear
Make sure you select Create folder references and Copy items if needed. This will make sure that the entire folder is constantly synced inside your Xcode project. Then to verify that the assets will be transferred to your device when building the project, go into Build Phases and then to Copy Bundle Resources and you should see the name of the folder, in my case, I have named it TextFiles.
Now because you have added your folder into the application's Main Bundle, you can access it by doing this:
let fm = FileManager.default
let path = Bundle.main.resourcePath?.appending("/TextFiles")
fm.enumerator(atPath: path!)?.forEach({ (e) in
if let e = e as? String, let url = URL(string: e) {
doSomethingWith(url.pathExtension)
}
})
The reason we need to do the Bundle.main.resourcePath before it and can't simply say /TextFiles is because if we say /TextFiles it looks for that folder starting from the system root, which is why it wasn't working before. It would be like having a folder in C:/Users/Abc123/Documents/TextFiles but the system is looking for it in C:/TextFiles.

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