NSManagedObject inserted in context, but not shown in tableview - core-data

Using Core Data in my App, I have a strange behaviour. I can add and remove objects using FirstResponder, and the objects are shown immediately in my tableView.
But if I want to add Objects programmatically , objects are only registered and not saved - nor shown in the tableView.
What I did :
Creating the PersistentContainer
class ViewController: NSViewController {
#IBOutlet var arrayCrtl: NSArrayController!
var container: NSPersistentContainer!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
container = NSPersistentContainer(name:"Document")
container.loadPersistentStores(completionHandler: { (storeDescription, error ) in
if let error = error { print ("\(error)") }
})
}
Then, programmatically adding a ManagedObject
let context = container.viewContext
let describer = NSEntityDescription.entity(forEntityName: "Event", in: context)!
let newEvent:Event = Event(entity:describer, insertInto:context)
container.viewContext.insert(newEvent)
print ( container.viewContext.registeredObjects)
Any idea what's missing ?

I simply forgot to set the ArrayController to "prepares content" in the attribute inspector:

Related

save uiimageview to coredata as binary data swift (5)

I am trying to save a imageview as a image to binary data in core data. My code is not working. It has a compile error. In View controller it is not regisitering cdHandler. All i want to do is save the the imaveview as binary data in a core data model.I have 2 classes a app delegate and a view controller.
CLASS VIEW CONTROLLER
import UIKit
import CoreData
class ViewController: UIViewController {
var canVasView = UIImageView()
#objc func hhh() {
let photo = self.canVasView.image
let data = photo!.pngData()
if cdHandler.saveObject(pic: data!){
}
}
}
APP DELEGATE
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "Model")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
class cdHandler: NSObject {
private class func getContext() -> NSManagedObjectContext {
let appdeleagetzz = UIApplication.shared.delegate as! AppDelegate
return appdeleagetzz.persistentContainer.viewContext
}
class func saveObject(pic: Data, userName: String) -> Bool {
let context = getContext()
let entity = NSEntityDescription.entity(forEntityName: "User", in: context)
let managedObject = NSManagedObject(entity: entity!, insertInto: context)
managedObject.setValue(pic, forKey:"pic")
managedObject.setValue(userName, forKey:"userName")
do {
try context.save()
return true
} catch {
return false
}
}
class func deletObject(user: User) -> Bool {
let context = getContext()
context.delete(user)
do {
try context.save()
return true
} catch {
return false
}
}
class func fetchObject() -> [User]? {
do {
let context = getContext()
return try context.fetch(User.fetchRequest())
} catch {
return [User]()
}
}
}
}
The error message, *Value of type 'AppDelegate' has no member named 'persistentContainer', explains the problem. Indeed, when I look at the code for your AppDelegate class, I can confirm that it has no member named 'persistentContainer'. (If I am reading it correctly, the last two lines in the file are closing curly brackets. The first one closes your cdHandler nested class, and the second one closes your AppDelegate class.)
Do the following exercise. In Xcode, click in the menu: File > New Project and select iOS, Application and Single View App. Name your new project Junk. Switch on the Core Data checkbox. Click button Create. After it is done, look at the AppDelegate.swift which Xcode created, and in the AppDelegate class, you see it contains 8 functions (func). The 7th one is lazy var persistentContainer. Aha! The compiler is telling you that you probably should not have deleted those 8 functions, persistentContainer in particular.
You should copy that persistentContainer func from that Junk project into your AppDelegate class in your real project. Or, to head off future trouble, consider copying most of the other 7 funcs also. As you can see, most of them don't do anything except provide comments with explanations that are useful for beginners. After you are done copying, close the Junk project. (I overwrite my Junk project with a new Junk project several times in a typical week, especially when answering StackOverflow questions.)
That should fix this particular error and answer this question. Onward to the next issue. :)
Response to comment that you still get the error with cdHandler
Having nothing else to go on, I presume that the error that you are referring to is the compiler error still in your screenshot. In other words, you are saying that adding the persistentContainer definition did not make it any better.
Well, it works for me. Please replace all of the code in your AppDelegate.swift class with the following, build and run it…
import UIKit
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
AppDelegate.cdHandler.testGetContext()
return true
}
lazy var persistentContainer: NSPersistentContainer = {
/*
The persistent container for the application. This implementation
creates and returns a container, having loaded the store for the
application to it. This property is optional since there are legitimate
error conditions that could cause the creation of the store to fail.
*/
let container = NSPersistentContainer(name: "Junk")
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
/*
Typical reasons for an error here include:
* The parent directory does not exist, cannot be created, or disallows writing.
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
* The device is out of space.
* The store could not be migrated to the current model version.
Check the error message to determine what the actual problem was.
*/
fatalError("Unresolved error \(error), \(error.userInfo)")
}
})
return container
}()
class cdHandler: NSObject {
private class func getContext() -> NSManagedObjectContext {
let appdeleagetzz = UIApplication.shared.delegate as! AppDelegate
return appdeleagetzz.persistentContainer.viewContext
}
class func testGetContext() {
let context = getContext()
print("getContext() succeeded, got \(context)")
}
class func saveObject(pic: Data, userName: String) -> Bool {
let context = getContext()
let entity = NSEntityDescription.entity(forEntityName: "User", in: context)
let managedObject = NSManagedObject(entity: entity!, insertInto: context)
managedObject.setValue(pic, forKey:"pic")
managedObject.setValue(userName, forKey:"userName")
do {
try context.save()
return true
} catch {
return false
}
}
class func deletObject(user: NSManagedObject) -> Bool {
let context = getContext()
context.delete(user)
do {
try context.save()
return true
} catch {
return false
}
}
}
}
You see that compiles with no errors. Also, it runs and the AppDelegate.cdhandler.getContext() method works. As you can see, in AppDelegate.application(application:didFinishLaunchingWithOptions:), I have added a call to a new method which I defined later,AppDelegate.cdHandler.testGetContext()`. It works perfectly.
Are you getting a different error now? If so, you need to specify whether it is a Build or Run error. In either case, copy and paste the text of the error into your question, and tell us where it occurs.

Displaying input text on different views

Was wondering if anybody could help on a simple problem
I have a UITextView on one page, where I want to enter text and store it in a string. Then when the next page is accessed, I would like that text to be displayed on that page, either in a new UITextView or some other way.
In my PostViewController.swift file (the first page) to get the input string, I have
#IBOutlet weak var postTextView: UITextView!
I tried making a new UITextView on the other view controller to try and display the string, and had the subsequent code, but can't figure it out from here.
#IBOutlet weak var copyText: UITextView!
let text: NSString = PostViewController().postTextView.text
???copyText = text??? (not sure if this is even close to right)
Any ideas would be appreciated and apologies for the noob question
In your PostViewController, implement prepareForSegue() to assign the value of its textfield to the variable in the second controller.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showSecondVC" { // Make sure the segue has this identity in Interface Builder
let vc = segue.destinationViewController as! SecondVC // Change that to the actual class name
vc.textFromVC1 = postTextView.text
}
}
In your second ViewController:
class SecondviewController: UIViewController {
var textFromVC1: String!
#IBOutlet weak var myTextField: UITextField!
override func viewDidLoad() {
myTextField.text = textFromVC1
}
}

Simple Swift WebView not working (Xcode 6 Beta 3)

I was writing a simple WebView in Swift, but everytime I try to launch it in the iOS Simulator I get these errors. What is going wrong?
import UIKit
class ViewController: UIViewController {
#IBOutlet var webview: UIWebView
var urlpath = "http://www.google.de"
func loadAddressURL(){
let requesturl = NSURL(string: urlpath)
let request = NSURLRequest(URL: requesturl)
webview.loadRequest(request)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loadAddressURL()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Error:
fatal error: unexpectedly found nil while unwrapping an Optional value
(lldb)
self uiwebview.ViewController 0x7987fc70 0x7987fc70
request NSURLRequest * 0x78ebfc40 0x78ebfc40
requesturl NSURL * "" 0x78ec0040
You simply haven't connected your UIWebView to the webview class property
Open the assistant editor, show your xib or storyboard at left, your view controller source file at right, click on the circle at the left of the webview property and drag into the UIWebView control. Once the connection is established, run the app and it should work now
I guess you get a white page because you test on the simulator. If you test on a real device you should be fine.
You need to put "!" after 'UIWebView' and unwrap "requesturl" to get your String value otherwise it's been an optional and you get error.
import UIKit
class WebViewController: UIViewController {
#IBOutlet var webview: UIWebView!
var urlpath: String = "http://www.google.de"
func loadAddressURL(){
let requesturl = NSURL(string: urlpath)
let request = NSURLRequest(URL: requesturl!)
webview.loadRequest(request)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loadAddressURL()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

Monotouch SplitView Example Cant Change ViewController

I am trying to learn how to use the UISplitViewController and I am using the "SplitView" example available from Monotouch. I understand how it works and communicates between the Master and Detail controllers.
Therefore it can't be hard to change the detail controller? So I have made a very small amendment and it doesn't work! I have read you must use the SetViewControllers but this doesn't exist in the Monotouch stack. Where am I going wrong?
It's exactly the same code as the example from Montouch except for the lines below:
public class MainSplitView : UISplitViewController
{
protected Screens.MasterView.MasterTableView masterView;
protected Screens.DetailView.DetailViewScreen detailView;
protected TestViewController testViewController; // *** Added this line
public MainSplitView () : base()
{
// create our master and detail views
masterView = new Screens.MasterView.MasterTableView ();
detailView = new Screens.DetailView.DetailViewScreen ();
masterView.RowClicked += (object sender, MasterView.MasterTableView.RowClickedEventArgs e) =>
{
detailView.Text = e.Item;
testViewController = new TestViewController(); // *** Added this line
ViewControllers[0] = masterView; // *** Added this line
ViewControllers[1] = testViewController; // *** Added this line
// the UISplitViewController.SetViewControllers does not exist! ???
};
ViewControllers = new UIViewController[] { masterView, detailView };
}
All help greatly appreciated!
Mike
Set ViewControllers exactly how do you do are doing it in the other place:
ViewControllers = new UIViewController[] { masterView, detailView };
Just do this:
ViewControllers = new UIViewController[] { masterView, testViewController };

MKAnnotationView RightCallOut button crashes my app when I click on it

I'm calling a service and returning a bunch of latitudes and longitudes which I'm then placing on a map using MapKit.
using MKAnnotationView I'm adding a RightCallOutButton to each annotation.
So I had to create a new MapDelegate. Code below.
If I click on the button I create the app crashes and I get an error from MonoTouch saying the selector is accings omething that has already been GC'd (garbage collected).
So my question would be, where should I set the RightCalloutAccessoryView and where should I create the button, if not in this code below?
public class MapDelegage : MKMapViewDelegate {
protected string _annotationIdentifier = "BasicAnnotation";
public override MKAnnotationView GetViewForAnnotation (MKMapView mapView, NSObject annotation) {
MKAnnotationView annotationView = mapView.DequeueReusableAnnotation(this._annotationIdentifier);
if(annotationView == null) {
annotationView = new MKPinAnnotationView(annotation, this._annotationIdentifier);
} else {
annotationView.Annotation = annotation;
}
annotationView.CanShowCallout = true;
(annotationView as MKPinAnnotationView).AnimatesDrop = true;
(annotationView as MKPinAnnotationView).PinColor = MKPinAnnotationColor.Green;
annotationView.Selected = true;
var button = UIButton.FromType(UIButtonType.DetailDisclosure);
button.TouchUpInside += (sender, e) => {
new UIAlertView("Testing", "Testing Message", null, "Close", null).Show ();
} ;
annotationView.RightCalloutAccessoryView = button;
return annotationView;
}
}
annotationView = new MKPinAnnotationView(annotation, this._annotationIdentifier);
...
var button = UIButton.FromType(UIButtonType.DetailDisclosure);
You should avoid declaring local variables to hold references you expect to outlive the method itself. Once there's no reference to annotationView or button the Garbage Collector (GC) is free to collect them (the managed part) even if it's native counterparts still exists. However when a callback to them is called you'll get a crash.
The easiest solution is to keep a list of them and (at the class level, i.e. a List<MKPinAnnotationView> field) clear the list when you destroy the view. The UIButton should not be necessary since there's a reference between the view and it.
NOTE: work is being done to hide this complexity from developers in future versions of MonoTouch. Sadly you cannot ignore such issues at the moment.

Resources