How to Get Assets.Xcassets File Names in an Array (Or Some Data Structure)

How to get Assets.xcassets file names in an Array (or some data structure?)

Assets.xcassets is not a folder but an archive containing all the images using Assets.car as its filename.

If you really want to read the assets file then you need to use some library that can extract the contents of the file like this one.

Or you can create a bundle in your project and drag all the images you have there. In my case, I have Images.bundle in my project. To get the filenames you can do the following:

let fileManager = NSFileManager.defaultManager()
let bundleURL = NSBundle.mainBundle().bundleURL
let assetURL = bundleURL.URLByAppendingPathComponent("Images.bundle")
let contents = try! fileManager.contentsOfDirectoryAtURL(assetURL, includingPropertiesForKeys: [NSURLNameKey, NSURLIsDirectoryKey], options: .SkipsHiddenFiles)

for item in contents
{
print(item.lastPathComponent)
}

SWIFT 3/4 Version:

let fileManager = FileManager.default
let bundleURL = Bundle.main.bundleURL
let assetURL = bundleURL.appendingPathComponent("Images.bundle")

do {
let contents = try fileManager.contentsOfDirectory(at: assetURL, includingPropertiesForKeys: [URLResourceKey.nameKey, URLResourceKey.isDirectoryKey], options: .skipsHiddenFiles)

for item in contents
{
print(item.lastPathComponent)
}
}
catch let error as NSError {
print(error)
}

List the Assets.xcassets contents

Files from your Assets.xcassets are not simply copied into you app bundle.

Instead, Xcode compiles them into a special file called a car file - think of it as a sort of ZIP archive of all your assets.

The .car file format has been reverse engineered, e.g. at https://blog.timac.org/2018/1018-reverse-engineering-the-car-file-format/ but reading its content is quite a lot of hassle.

Load array of images using group in xcassets

You cannot introspect an asset catalog. So you cannot ask it questions like what "folders" Set1 contains, or what images Birds contains.

If you need that sort of introspection, don't use an asset catalog. Use folder references embedded into the top level of your app bundle. Now you have real folders and files, and you can navigate the folders and ask what image files they contain using ordinary FileManager methods.

How to create an array of images from assets folder in Swift 5?

I think load 50 images on an array is not a good idea. I know you are following a tutorial.

For more same types of images, you can try this.

  • Try all image name prefixes are the same. Like: Dice1, Dice2,
    Dice3... Dice50 // Here the prefix is Dice
  • Get a random number between 0-49
  • Suppose you get a random number 30. Now you can simply get the image by this way

    let randomNumber = 30  
    let image = UIImage(named: "Dice\(randomNumber)")

In this way not need to create an array with 50 images.

Swift: How to get image name from assets

You cannot do what you are describing while storing the images in the Assets Catalog. Fetching a resource from an Assets Catalog relies upon your knowing its actual name.

Instead, store these folders directly at the top level of your app bundle. Now you have an actual folder that you can get a reference to, and can ask the FileManager for the names of the images in the folder.

Sample Image

Example (Swift 2.2, sorry):

let f = NSBundle.mainBundle().URLForResource("carPix", withExtension: nil)!
let fm = NSFileManager()
let arr = try! fm.contentsOfDirectoryAtURL(f, includingPropertiesForKeys: nil, options: [])
print(arr) // the URLs of the two jpg files

Is it possible to count pictures in asset catalog with particular prefix?

It might be easier to use folders instead of Images.xcassets. Create a hierarchy you like on your computer and drag this into your Xcode project. Make sure you select:

Create folder references for any added folders

Then because you now have folder references when building your app you can iterate over items inside those folders using a loop.

For example I dragged in a folder called "Cocktail" and created the reference. Now i can iterate over the items inside this folder using:

let resourcePath = NSURL(string: NSBundle.mainBundle().resourcePath!)?.URLByAppendingPathComponent("Cocktail")
let resourcesContent = try! NSFileManager().contentsOfDirectoryAtURL(resourcePath!, includingPropertiesForKeys: nil, options: NSDirectoryEnumerationOptions.SkipsHiddenFiles)

for url in resourcesContent {
print(url)
print(url.lastPathComponent)
print(url.pathExtension!) // Optional

}

The url.lastPathComponent is the filename of the image (e.g. Cocktail_01.jpeg) and the url itself is the complete path of the image.

If you maintain a structure of folders it is very easy to iterate over them, if you want all the images in the same folder than you can create an array with just the image names you need and iterate over that using:

// The Array of Image names
var cocktailImagesArray : [String] = []

// Add images to the array in the 'for url in resourceContent' loop
if (url.lastPathComponent?.containsString("Cocktail")) {
self.cocktailImagesArray.append(url.lastPathComponent)
}

This way you have all the images which contain Cocktail and have added them to your array. Now you can simple iterate over your freshly created array using:

for imageName in self.cocktailImagesArray {
// Do something
}

Loading images from Images.xcassets

To start with my answer I will recommend, DON'T do it.

Its really an overkill for your app to load 100 images and to store them in memory, at once, and the app would definitely go under some memory pressure.

In Xcode 5, .xcassets is still the best place to keep your images in app bundle. For further details you might be interested in Apple Asset Catalog documentation. However, rather than loading and storing images to NSArray, I would recommend you to store their identifiers (actually the image names as added to .xcassets) in the array. Also it would be helpful if you store the image identifiers to some NSString* const beforehand.

So your coding structure should look something like the following:

//image names
NSString* const kImage1 = @"image1";
NSString* const kImage2 = @"image2";
NSString* const kImage3 = @"image3";
//...etc

NSArray* imageIdentifiers = @[kImage1, kImage2, kImage3,...];

//...

And then to load individual image from bundle you could use:

UIImage* img = [UIImage imageNamed:kImage3]; //loads image3 from bundle and caches

Or to traverse through all images you might use:

for (NSString* identifier in imageIdentifiers) {
@autoreleasepool { //make sure your image data gets disposed after use
UIImage* img = [UIImage imageNamed:identifier];
//... use img, etc.
}
}

And finally, imageNamed: method of UIImage class, caches an image in system cache. So you won't have to worry about reloading it from file, if you reuse one.



Related Topics



Leave a reply



Submit