Load Multiple pList Files into a View - swift

I am creating a quiz app and the data are in the pList.
I have multiple pLists representing different categories. I do not want to merge these pList into one single file because I will use them separately for another purpose.
My question is, can we read or load multiple pList files into a View at once? If yes, how?
I am using the following code to load single pList files:
let path = Bundle.main.path(forResource: "pListData", ofType: "plist")
let dict = NSDictionary(contentsOfFile: path!)
pListData = (dict!["Tips"]! as AnyObject) as? Array
I am presenting a single data (a question) from a single pList each time a question is loaded. How do you randomly read from multiple pList sources instead of from a single one?

Related

Swift Images cannot be read in Asset Catalog

I'm trying to save some images into my bundle. The images reads just fine when I save them in the main bundle.
in main bundle
However, if I place them into the asset catalog, they can no longer be read.
In asset catelog
Below are the codes I use to access them. If I save the pictures inside the asset catalog, the for item in items loop doesn't pick up any of the pictures.
override func viewDidLoad() {
super.viewDidLoad()
let fm = FileManager.default
let path = Bundle.main.resourcePath!
let items = try! fm.contentsOfDirectory(atPath: path)
for item in items {
if item.hasPrefix("nssl") {
pictures.append(item)
}
}
}
There's no documented way to iterate through the images contained in an xcasset file. At build time the assets get compiled to a .car file, but the only way to read images out of the asset is through UIImaged(named:).
If you need to be able to iterate through some resources in this way, it's best to store them in a simple folder inside your bundle.

Save and retrieve image in Swift 3.0

I am really confused of all the different possibilities Swift has to save data and retrieve data. Save and retrieve data through userDefaults is easy, but for storing a lot of images this is not the best way to do it. Then there is Core Data, which is I think to complicated to use for such a simple task. I continued to read about DocumentDirectory, I think this is a good way to save and retrieve data. However, all the tutorials are mostly from swift 2.0 and below, and I can not read that very well. Is the document directory the best way to store and retrieve images? I am making an online application which contains downloading images from users. However, the images are all the same from the same user, so I want to store the images offline to save some bandwidth.
I want to store and retrieve images with a path I can specify in a String. Every user has a unique identifier which I want to use as a path. How can I accomplish this?
Saving in your file system is definitely the best approach to use in this scenario.
Have a look to this answer:
https://stackoverflow.com/a/39896556/5109911
if let data = UIImageJPEGRepresentation(image, 0.8) {
let filename = getDocumentsDirectory().appendingPathComponent("copy.png")
try? data.write(to: filename)
}
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
where image is your UIImage
To Store Image in User default you can just simply create an extension of UI image view like 👇🏻 below Code Click the link to show code
https://i.stack.imgur.com/xEhcr.png
How to Use::- yourimageviewName.saveImage(),OtherImageViewName.loadImage()
https://i.stack.imgur.com/wcrNX.png

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)
}

Swift - Storing data in directory using NSSearchPathForDirectoriesInDomains, but directory always changes?

I have a sound recorder app where recorded sounds are stored like this:
let dirPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0] as String
var pathArray = [dirPath, recordingName]
let filePath = NSURL.fileURLWithPathComponents(pathArray)
All file path URL's are stored in an array (put into NSUserDefaults) for easy access.
I can play the files if they're played on the same run as when they're recorded, but opening and closing the simulator back up will result in the file path being wrong (since the app-id folder at ~/Library/Developer/CoreSimulator/Devices/Device-ID/data/Container/Data/Application/app-id-folder/Documents/filename.wav will have changed name). How can I change the array containing the file URL's to have the updated app-id folder name each time the app is run? (currently it's just an array of strings which are converted to NSURL type when necessary). Or even simpler, is it possible to save to the users home directory or somewhere where you don't need to deal with changing folder names?
I solved it by creating an NSUserDefaults array of just the file names (like [audio1.wav,audio2.wav]) and calling the NSSearchPathForDirectoriesInDomains on each new viewdidload, then combining the two into a new string. Like this (code below would call the second audio file in the array):
let dirPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory,.UserDomainMask,true)[0] as String
var filesNamesWithWav = defaults?.objectForKey("filesNamesWithWav") as NSArray
var newpath = "\(dirPath)/" + "\(filesNamesWithWav[1])"

How to get ID3 tags for media files on iPhone

I need some help.
The situation looks like this:
I can get list of media files (mp3s, m4as, m4vs an so on) with link to the file (looks like:
http://10.0.1.1/Media/Files%20Folder/File%20Itself.m4v
So I get an array consisting of links to these files.
I need to display these items in UITableView with corresponding tags (Genre, Artist etc.) and most importantly, album art (it's embedded in file).
How can I fetch that information? If possible, without loading whole media file.
Thanks for any help.
I wrote a class for this
It's called metadataRetriever. It returns an array of the
artist,
song,
and album
as NSStrings (in that order)
It's really fast and is safe for synchronous use.
One caveat, it doesn't work for .m4a's because the id3 info for .m4a's is different.
You'll want to use AVURLAsset along with the method -loadValuesAsynchronouslyForKeys:completionHandler:.
Also note that the docs say
AVAsset and other classes provide their metadata “lazily” (see AVAsynchronousKeyValueLoading), meaning that you can obtain objects from those arrays without incurring overhead for items you don’t ultimately inspect.
So I'm guessing you won't run into problems of loading the whole file.
Check out the AVMetadataItem API:
let asset = AVAsset(url: url)
assert(asset.isReadable)
let artwork = AVMetadataItem.metadataItems(from: asset.metadata, filteredByIdentifier: .commonIdentifierArtwork).first?.dataValue
let artist = AVMetadataItem.metadataItems(from: asset.metadata, filteredByIdentifier: .commonIdentifierArtist).first?.stringValue
let title = AVMetadataItem.metadataItems(from: asset.metadata, filteredByIdentifier: .commonIdentifierTitle).first?.stringValue
let albumName = AVMetadataItem.metadataItems(from: asset.metadata, filteredByIdentifier: .commonIdentifierAlbumName).first?.stringValue
let duration = asset.duration.seconds