App Hangs when saving in core data - swift

I'm using swift core data to save user's info within the app but when its saving current users data (name,bio, 3-4 photos) it hangs for 2-3 seconds until it saves the data. What is the best way to avoid this hanging of the app? this is the code I'm using
for photo in photos {
let data = NSData(contentsOfURL: NSURL(string: photo.url!)!)
let newimg = UIImage(data: data!)
newusersImages.addObject(newimg!)
}
mayBeUser.name = currentuser!.objectForKey("name") as! String
let arrayData = NSKeyedArchiver.archivedDataWithRootObject(newusersImages)
let locationData = NSKeyedArchiver.archivedDataWithRootObject(currentuser!.objectForKey("location")!)
mayBeUser.photos = arrayData
mayBeUser.location = locationData
mayBeUser.about = currentuser!.objectForKey("about") as! String
mayBeUser.setValue(currentuser!.objectForKey("age") as! Int, forKey: "age")
mayBeUser.objectId = currentuser!.objectId!
mayBeUser.lastSeen = currentuser!.objectForKey("lastSeen") as! NSDate
try! context.save()
print("Current User Updated")
when the user has 10-15 friends , it takes hangs for a minute to save/update all the info/data of the users.

Here's how I'd do it. Now obviously you don't want the UI to hang, so you'll want to use a managed object context that has a private queue concurrency type. More info on that here. Specifically, look at the part at the end where he details how to create the export function.
Now, since you're saving data to the persistent store in this case, you might not want the user to go around changing stuff while their previous changes are being saved, in this case you might want an interim screen showing the progress of the save.

You (and your app) are having to work hard to save all that photo data into one attribute of your User entity. Instead, restructure your data model:
Create a separate Photo entity for the photos.
Don't store the photo image data in CoreData - just store a string with the URL.
Add a to-many relationship from User to Photo, instead of the photos attribute.
Incidentally, I would avoid using objectId as an attribute name: it's so close to CoreData's objectID it will cause confusion.

Related

Fetch data from CoreData for iOS 14 widget

I want to display data fetched from Core Data in a widget. But #FetchRequest doesn’t work on widgets.
As I understand, we have to create an app group and make a shared persistent container.
What I want to know is how to read (fetch) data on widgets from that shared persistent container or simply, how to display data fetched from Core Data in widgets.
First you need to create an AppGroup which will be used to create a Core Data Persistent Container (here is a good explanation how to do it)
Then you need to create your own CoreData stack (an example can be found when you create a new empty project with CoreData enabled).
Accessing Core Data Stack in MVVM application
Assuming you have already created your Core Data model (here called DataModel), you now need to set the container url to your custom shared container location:
Share data between main App and Widget in SwiftUI for iOS 14
let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: <your_app_group>)!
let storeURL = containerURL.appendingPathComponent("DataModel.sqlite")
let description = NSPersistentStoreDescription(url: storeURL)
let container = NSPersistentContainer(name: "DataModel")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { ... }
Now you can get the managedObjectContext from your shared Persistent Container:
let moc = CoreDataStack.shared.managedObjectContext
and perform a fetch request with it (more information here)
let predicate = NSPredicate(format: "attribute1 == %#", "test")
let request = NSFetchRequest<SomeItem>(entityName: "SomeItem")
let result = try moc.fetch(request)
Apart from all the links above I recommend you also read this tutorial about Core Data:
Core Data with SwiftUI Tutorial: Getting Started
Here is a GitHub repository with different Widget examples including the Core Data Widget.
For people who did all the work above, and finally can get the connection to your Core Data (e.g. you can get the count of request), but can't fetch the request, is mostly because that the entity you're fetching contains transformable type, and for some reason this error occurred: Cannot decode object of class, try fix this.

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

Saving to specific core data object in Today Extension

Working on a part of my iOS project that needs to refer to a specific object that the user selects in the main application that is set through a toggle switch that activates the specified object to be used in a Today Extension to record simple objects created by the user in the Today Extension. I am unsure how to go about doing this specifically. I thought about using NSUSerDefaults as the go to method for specifying that object but this is all entirely new to me. Has anyone gone down this path before on here? Does anyone know a way to refer to the specific object you want to store to in the Today Extension?
You can save a reference to a specific managed object by using the objectID property (an instance of NSManagedObjectID), which can be converted to a URI. The URI can then be converted to NSData, which you can save in user defaults.
To save the reference, get the object's ID as a URI:
let objectIDURI = newManagedObject.objectID.URIRepresentation()
Then convert to NSData and save:
let objectIDURIData = NSKeyedArchiver.archivedDataWithRootObject(objectIDURI)
NSUserDefaults.standardUserDefaults().setObject(objectIDURIData, forKey: "savedID")
To get the object back, load the NSData and convert back to an NSURL (the following is simplified, you'll have to handle optionals properly):
let savedObjectIDURIData = NSUserDefaults.standardUserDefaults().objectForKey("savedID") as? NSData
let savedObjectIDURI = NSKeyedUnarchiver.unarchiveObjectWithData(savedObjectIDURIData!) as? NSURL
Then convert the ID back to an NSManagedObjectID and get the managed object:
let savedObjectID = context.persistentStoreCoordinator?.managedObjectIDForURIRepresentation(savedObjectIDURI!)
let savedObject = context.objectWithID(savedObjectID!)
At this point savedObject is the managed object that was saved above.

Text and table view data storage in swift

Could anyone tell me what the way of storing a long text in a swift app is. Let's suppose I have an app that has a table view and when I chose a row I go to a new scene where I have a big page filled by text.
The question is where do I have to store the data of the table's row and the whole text? And how?
Do I have to make a model? Is it just one for both the table and the text? Or more than one. Is there any tutorial that explains this exact situation or close to it?
You could use Parse.com framework to retrieve data from a database. There is a lot of documentation on this.
In this link you can find a tutorial that will explain you how to load data from Parse and show it in your UITableView.
Storing Local (in-memory store):
For storing without a internet connection you could use Core Data Stack with NSInMemoryStoreType as storeType. This tutorial will give you a nice idea on how it works.
You can declare a model like it follows:
struct CoreDataModel {
let name: String
let bundle: NSBundle
init(name: String, bundle: NSBundle)
// other properties & methods
}
And then manage it with:
let model = CoreDataModel(name: "MyModel", bundle: myBundle)
let stack = CoreDataStack(model: model,
storeType: NSInMemoryStoreType,
concurrencyType: .MainQueueConcurrencyType)
// Use context
stack.managedObjectContext

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