overwrite a core data binary data item - arrays

My swift code below saves 3 images. What I want to do is overwrite iamgedata2 is func press. Imagedata2 should be replaced with Gwen. So the order should be Gwen Gwen Gwen instead of Gwen gwen2 Gwen. I don't know what really to put in func press to achieve this goal.
import UIKit; import CoreData
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .orange
let gwen = UIImage(named: "blank")
let gwen2 = UIImage(named: "g.jpg")
if let imageData = gwen.self?.pngData() {
CoredataHandler.shareInstance.saveImage(data: imageData)
}
if let imageData2 = gwen2.self?.pngData() {
CoredataHandler.shareInstance.saveImage(data: imageData2)
}
if let imageData3 = gwen.self?.pngData() {
CoredataHandler.shareInstance.saveImage(data: imageData3)
}
}
#objc func press(){
CoredataHandler.shareInstance.saveImage(data: 1)
return
}
}
class CoredataHandler : NSManagedObject {
static let shareInstance = CoredataHandler()
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
private class func getContext() -> NSManagedObjectContext {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
return appDelegate.persistentContainer.viewContext
}
func saveImage(data: Data) {
let imageInstance = Information(context: context)
imageInstance.pic = data
do {
try context.save()
} catch {
print(error.localizedDescription)
}
}
}

If you want a Core Data entity that can store more than one image, you have a few options:
Declare multiple image properties
Instead of just having a pic property, have more than one. As many as you like. Name them pic1, pic2, pic3, etc, or whatever seems best for your app. In code, read or write whichever makes sense at the time.
This is easy but not flexible, since your code can only save up to the number of attributes you declare in the model.
Use an array property with transformable
With a transformable attribute you can store any data that can be converted to a Data. In your case you'd do something like this:
Two things to notice: The type is transformable, and the custom class is [Data]. Xcode will generate code where the property type is [Data]?. You can save as many Data blobs as you want in it, representing however many images you want.
This is also easy but may use a lot of memory, because you can't access one image without loading all of them into memory at once. If you always load all of them anyway then it's no different. If you often load only one of them, this technique might use a lot more memory (e.g. 4 images would mean around 4x as much memory used).
Use a separate entity to hold the image and a to-many relationship
With this approach you'd create a new Core Data entity that only holds the image. Your existing entity would have a to-many relationship to this entity. You'd create as many image-only instances as you want, and the relationship would mean they were all available at any time.
You would probably want to make sure the to-many relationship is ordered, otherwise the images would be an unordered set that could be in any order.
This is a little more complex to write but it's flexible and doesn't have the potential memory problems of other approaches.

Related

Swift: Cannot add element in Array from another object

I am struggeling with swift syntax . I want to add objects to an array but I have syntax errors.
The array is located in class Document, and the class that should add objects is in class Viewcontroller.
The array is of type Content:
public class Content: NSObject {
#objc var bankAccSender: String?
#objc var bankAccReceiver: String?
Declaration snippest in Document:
class Document: NSDocument {
var content=[Content]()
override init() {
super.init()
self.content = [Content]()
// force one data record to insert into content
content += [Content (… )] // checked with debugger
The ViewController has assigned the represented Object
contentVC.representedObject = content
But adding data in ViewController gives a compiler error „Type of expression is ambiguous without more context“:
var posting = Content(…)
self.representedObject.append(posting)
Hope you can help..
You can't append an element to an object of type Any. What you need is to replace the existing value with a new collection:
representedObject = (representedObject as? [Content] ?? []) + CollectionOfOne(posting)
representedObject is of type Any?, which is a very difficult type to work with in Swift. Since you already have a content property, I would probably adjust that, and then re-assign it to representedObject.
You can also try this (untested), as long as you are certain that the type is always [Content]:
(self.representedObject as! [Content]).append(posting)
It's possible you'll need some more complex like this:
(self.representedObject as! [Content]?)!.append(posting)
As I said, Any? is an incredibly obnoxious type. You probably want to wrap this up into a function. Or I you can avoid using representedObject, then I would recommend that. In many cases you don't need it. It's often just a convenience (in ObjC; in Swift, it's very hard to use).

how can i pass alot of data from viewController to another on without using segue?

I want to pass a UIimage from viewController to another without using segue and i keep searching for this problem for weeks. Also, i tried to do it using notificationCenter, delegate and protocol but it didn't work with me so help please.
This is a screenShot describe what i want to do exactly.
enter image description here
Also, this is my code for the viewController which i want to pass the thor image from it when the pass Label button is clicked .
import UIKit
protocol UserChosePhoto {
func userHasChosen(image: UIImage)
}
class passingDataViewController: UIViewController {
#IBOutlet var Label: UILabel!
#IBOutlet var image1: UIImageView!
var image: UIImage? = nil
var delegate: UserChosePhoto? = nil
override func viewDidLoad() {
super.viewDidLoad()
image1.image = image
}
#IBAction func passLabel(_ sender: Any) {
func tapped() {
if (delegate != nil) {
self.delegate!.userHasChosen(image: image1.image!)
}
}
}
}
and this is the code for the viewController which i want to display thor image in it .
import UIKit
class receivingDataViewController: UIViewController, UserChosePhoto {
#IBOutlet var label2: UILabel!
#IBOutlet var image2: UIImageView!
var usedImage: UIImage? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
func userHasChosen(image: UIImage) {
usedImage = image
print("delegation: \(image)")
}
}
I'm seeing a few things missing, along with some Swift coding conventions not being followed. So let's start with your UserChosePhoto protocol, which is pretty good. But - why not make your code readable?
protocol PassingDataViewControllerDelegate {
func userHasChosen(image: UIImage)
}
Sure, what you have will work, but adding Delegate to the end of your name (along with which VC you are using this with) make everyone know what you are doing.
Now you need to properly set up your first view controller:
class PassingDataViewController: UIViewController {
var delegate: PassingDataViewControllerDelegate? = nil
func tapped() {
if (delegate != nil) {
self.delegate!.userHasChosen(image: image1.image!)
}
}
}
Again, very close to your code - I just capitalized your view controller's class name. This is how Swift coders do it. Oh, and since I changed the name of the portal, that needed to be changed to.
But there's one more thing - you have a second way to code this:
class PassingDataViewController: UIViewController {
var delegate: PassingDataViewControllerDelegate! = nil
func tapped() {
delegate.userHasChosen(image: image1.image)
}
}
This results in a couple of things. Obviously, the delegate call is simpler. But more importantly, if you don't set up things correctly in your second view controller, your app crashes. (Sometimes, that's actually a good thing!)
Here's where I think you didn't do things right - the second VC:
class ReceivingDataViewController: UIViewController, PassingDataViewControllerDelegate {
var usedImage: UIImage? = nil
let passingDataViewController = PassingDataViewController()
override func viewDidLoad() {
super.viewDidLoad()
passingDataViewController.delegate = self
}
func userHasChosen(image: UIImage) {
usedImage = image
print("delegation: \(image)")
}
}
Now, several things.
First, note that I'm creating an instance of the first VC - that's needed. Delegation is always a 1:1 kind of communication. What is still missing (because you haven't mentioned it in your question) is how the first VC is being presented. I know you don't want to use a segue, but how is your app "flow" going from the first to the second view controller? Usually without a segue that means presenting it modally (like you would with UIImagePickerController). You can also add both the view controller and it's view as a child VC and view in the hierarchy.
Second, I'm telling the first VC that the second VC is the it's delegate. If instead of using optionals (var delegate: PassingDataViewControllerDelegate? = nil) you force-unwrap things (var delegate: PassingDataViewControllerDelegate! = nil) you'd see your app crash because the second VC isn't the delegate for the first VC without passingDataViewController.delegate = self.
FINAL NOTE:
While I was writing this #TLG_Codin provided an answer. It could work - but *where is userImage declared as a public variable? In one of two places:
Globally, as in outside of a class. That's called a singleton, and be very, very careful on doing this. Since it's global, anyplace in your app can change it. That's why singletons are generally frowned upon.
Inside your first VC. The problem there is - how are you presenting this VC? Again, you've mentioned you don't want to use a segue. So... you're back to my note about presenting the first VC from the second or adding the VC and it's view to the hierarchy. Either way? Delegation works perfectly, and at the moment you wish to tell interested classes (in this case the second VC) that userImage has changed, you do.
Try using public variable. It will let you store anything you want in it and access it from anywhere in your project.
for example, put this line anywhere outside of any class:
public var userImage: UIImage? = nil
and then you can use it anywhere in your code by using userImage like any other variable.
Or, if you have multiple variables, you can create a struct with static variables:
struct sharedVariables {
static var userImage: UIImage? = nil
static var userList: [Any] = [64, "Hello, world!"]
static var integer: Int = 300
// Or add anything you want; just make sure to start with 'static'
}
And then you can use the variables in the struct like that:
sharedVariables.userList
Of course, there are more ways to do what you asked for, but this is the simplest one.

Lazy initialisation of individual array elements

In Swift, lazy properties allow us to only initialise a class member when we ask for it instead of directly at runtime - useful for computationally expensive operations.
I have a class in Swift 4 that is responsible for initialising a strategy from an array of compile-time (developer-hardcoded) provided StrategyProtocol objects. It looks something like this:
class StrategyFactory {
private var availableStrategies: [StrategyProtocol] = [
OneClassThatImplementsStrategyProtocol(),
AnotherThatImplementsStrategyProtocol() // etc
]
public func createStrategy(): StrategyProtocol {
// Depending on some runtime-calculated operation
// How do I do this nicely here?
}
}
However, from my understanding, placing () at the end of each strategy initialises the objects(?), when I may only want to create one depending on certain runtime conditions.
Either way, is it possible to place lazy somewhere around the values in an Array class member to only instantiate the one I want when I ask for it? Or would I have to go about this with closures or some other alternative?
Current attempt
Is this doing what I think it is? Until I get the first element of the array and execute it, it won't actually instantiate the strategy?
private var availableStrategies: [() -> (StrategyProtocol)] = [
{ OneClassThatImplementsStrategyProtocol() }
]
Your "Current attempt" does what you think it does. You have an array
of closures, and the strategy is initialized only when the closure is
executed.
A possible alternative: Store an array of types instead of
instances or closures (as Zalman Stern also suggested).
In order to create instances on demand, a
init() requirement has to be added to the protocol (which must then
be satisfied by a required init() unless the class is final,
compare Why use required Initializers in Swift classes?).
A possible advantage is that you can query static properties
in order to find a suitable strategy.
Here is a small self-contained example, where createStrategy()
creates and returns the first "fantastic" strategy:
protocol StrategyProtocol {
init()
static var isFantastic: Bool { get }
}
class OneClassThatImplementsStrategyProtocol : StrategyProtocol {
required init() { }
static var isFantastic: Bool { return false }
}
final class AnotherThatImplementsStrategyProtocol : StrategyProtocol {
init() { }
static var isFantastic: Bool { return true }
}
class StrategyFactory {
private var availableStrategies: [StrategyProtocol.Type] = [
OneClassThatImplementsStrategyProtocol.self,
AnotherThatImplementsStrategyProtocol.self // etc
]
public func createStrategy() -> StrategyProtocol? {
for strategy in availableStrategies {
if strategy.isFantastic {
return strategy.init()
}
}
return nil
}
}
ANYCLASS, META TYPE AND .SELF may answer your question. (I am not expert on Swift, but use of metaclasses is likely what you want and Swift, as I expected, appears to support them.) You can look through this Stack Overflow search.
EDIT: In case it wasn't clear, the idea is to have the array of strategies contain the metaclasses for the protocols rather than instantiations. Though this depends on whether you want a new strategy object for each instantiation of the class with the lazy property or whether strategies are effectively global and cached ones created. If the latter, then the lazy array approach for holding them might work better.

query user objectIDs stored in an array swift

I am trying to make groups of users in a class that will queried to form a group chat. I have stored the objectId's of each user in the group in an array. Then I save the array to Parse.
I am having trouble figuring out how to query the array, and then compare the objectID's with the _User class so the group members can be identified by name and profile picture.
Right now this is the code I have, but I know that it isn't the right method. Does anyone have any advice? Thanks!
class squadDetailInformation: UIViewController{
var currentObject: PFObject?
var squadmemberstrial: NSArray = []
override func viewDidLoad() {
super.viewDidLoad()
if let object = currentObject{
squadmemberstrial = (object.objectForKey("SquadMembers") as? NSArray)!
let user : PFUser = object.objectForKey("objectID") as! PFUser
let queryUsers = PFUser.query()
queryUsers.getObjectInBackgroundWithId(user.objectId, block: {
(userGet :PFObject!,error : NSError!) -> Void in
})
}
}
}
Don't use an array of object ids. An array of proper pointers would be better, but still isn't ideal. Instead you should use a relationship as you can directly query it and you can also use the relationship query in other queries as a filter.

Passing data between two containers in a same viewcontroller

I'm new to iOS programming, I read a lot of tutorials and forums but I still can't figure the best way to manage a project.
What I want is the iPad screen to display a CollectionView and a TableView side by side.
Actions in the CollectionView should change TableView content. SplitViewController won't do the job because of the fixed size of the split.
For now I'm using Storyboard, I created a ViewController and added two ContainerViews in it. Each container is linked by an XCode generated segue to a view controller (LeftViewController and RightViewController).
I'm trying to figure the smartest way to manage actions on the LeftViewController and send changes to the RightViewController.
I would like to use Storyboard that seems more elegant, but I'm not sure how to implement this.
Assuming you know the way to establish delegate methods (#protocol, see here for links), the key elements will be grabbing the two viewControllers embedded in containers as they are being loaded, setting the primary viewController as delegate, and sending the messages when something changes. For starters, if communication needs to flow both ways between controllers, set up an instance variable for each VC.
Given VCPrime, CollectionVC, and TableVC:
First, in storyboards, name each of your segues (from the containerViews to the VCs). In VCPrime, implement prepareForSegue:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"collection"]) {
self.collectionVC = (CollectionVC *)[segue destinationViewController];
self.collectionVC.delegate = self;
}
if ([segue.identifier isEqualToString:#"table"]) {
self.tableVC = (TableVC *)[segue destinationViewController];
self.tableVC.delegate = self;
}
}
You must also implement the delegate methods in VCPrime, and declare CollectionDelegate, TableDelegate, or however you named them.
In CollectionVC, when someone selects something (or whatever), check that the delegate responds to your delegate method, then send that message:
if ([self.delegate respondsToSelector:#selector(doSomething)]) [self.delegate doSomething];
Then alter TableVC in the method that is called.
This is just a quick rundown. The internets are alive with great code examples.
I think I might have an improvement in Swift (the answer is old but I was facing this problem a day ago). I re-implemented the above in Swift, but with a twist. Instead of setting the VCPrime as a delegate for for both CollectionVC and TableVC, I would make the TableVC a delegate of CollectionVC. That is because CollectionVC needs to control TableVC. In general we can call a "master VC" the one that controls and the "delegate VC" the one that is controlled. In order to make sure that both VC are actually instantiated when I set one as the delegate of the other, I use Swift optionals and optional bindings. Here is a sample of code" (note that the master needs to have a "delegate" property and you might want to declare the appropriate protocols):
import UIKit
class ContainerController: UIViewController {
private var masterViewController: myMasterViewController?
private var delegateViewController: myDelegateViewController?
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "myMasterViewController" {
masterViewController = segue.destinationViewController as? myMasterViewController
} else if segue.identifier == "myDelegateViewController" {
delegateViewController = segue.destinationViewController as? myDelegateViewController
}
if let master = masterViewController, delegate = delegateViewController {
println("Master and delegate set")
master.delegate = delegate
}
}
}

Resources