Coredata fetchRequest breaks if there is nothing stored - ios

I have my coredata set up and saving and fetchRequests work well. In this case I am fetching the first object saved in 'Item' but if the fetchResult is empty I do not want to call my method 'displayDataInLabel' as if there is nothing in it this method breaks (i'm guessing because the is nothing at 'objectAtIndex:0'
-(void)viewDidAppear:(BOOL)animated
{
if (_fetchResultsController.fetchedObjects == nil) {
return;
}
else
[self displayDataInLabel];
}
-(void)displayDataInLabel
{
Item *thisItem = [_fetchResultsController.fetchedObjects objectAtIndex:0];
NSLog(#"test item %#", thisItem.name);
}

It is not sufficient to check for nil because the result, even if nothing is found, will still be a valid (empty) array, which is not nil.
Instead, check if the count property of the result is zero.

Related

Delete duplicated object in core data (swift)

I'm saving objects to core data from a JSON, which I get using a for loop (let's say I called this setup function.
Because the user might stop this loop, the objects saved in core data will be partial. The user can restart this setup function, restarting the parsing and the procedure to save object to core data.
Now, I'm getting duplicated objects in core data if I restart the setup().
The object has an attribute which is id.
I've thought I could fetch first objects that could eventually already exist in core data, save them to an array (a custom type one), and test for each new object to add to core data if already exist one with the same id.
The code used is the following:
if !existingCards.isEmpty {
for existingCard in existingCards {
if id == existingCard.id {
moc.deleteObject(existingCard)
println("DELETED \(existingCard.name)")
}
}
}
...
// "existingCards is the array of object fetched previously.
// Code to save the object to core data.
Actually, the app return
EXC_BAD_ACCESS(code=1, address Ox0)
Is there an easier way to achieve my purpose or what should I fix to make my code work? I'm quite new to swift and I can't figure other solution.
The main purpose is to delete duplicated core data, BTW.
Swift 4 code to delete duplicate object:
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Card")
var resultsArr:[Card] = []
do {
resultsArr = try (mainManagedObjectContext!.fetch(fetchRequest) as! [Card])
} catch {
let fetchError = error as NSError
print(fetchError)
}
if resultsArr.count > 0 {
for x in resultsArr {
if x.id == id {
print("already exist")
mainManagedObjectContext.deleteObject(x)
}
}
}
At the end, I managed to make it work.
I had to rewrite my code, because I realized moc.deleteObject() works with a fetch before, which in my previous code wasn't in the same function, but it was in viewDidLoad().
// DO: - Fetch existing cards
var error: NSError?
var fetchRequest = NSFetchRequest(entityName: "Card")
if let results = moc.executeFetchRequest(fetchRequest, error: &error) as? [Card] {
if !results.isEmpty {
for x in results {
if x.id == id {
println("already exist")
moc.deleteObject(x)
}
}
}
} else {
println(error)
}
No more existingCards, the result of the the fetch is now processed as soon as possible. Something isn't clear to me yet, but now my code works. If you have any improvements/better ways, they're welcome.
P.S.: I actually found Apple reference useful but hard to understand because I don't know Obj-C. Often I can figure what the code do, but in swift functions and properties are a bit different.

Is -[NSDictionary setObject:nil forKey:] the same as -[NSDictionary removeObjectForKey:]?

I'm reading through some source code and I noticed the following API, where the developer passes in nil if they want an object to be removed.
- (void)setSomeStatus:(SomeStatusObject *)status {
if (status != nil) {
[store setObject:status forKey:SOME_STATUS_KEY];
} else {
[store removeObjectForKey:SOME_STATUS_KEY];
}
}
My specific question is if the above can be reduced to
- (void)setSomeStatus:(SomeStatusObject *)status {
[store setObject:status forKey:SOME_STATUS_KEY];
}
Or alternatively
- (void)setSomeStatus:(SomeStatusObject *)status {
store[SOME_STATUS_KEY] = status;
}
No, they are not equivalent. In fact, passing nil to setObject:forKey: (either the value or the key) will result in a runtime exception.
You can't set a value to nil using setObject:forKey.
NSDictionary wants an object, even if that object represents NULL, and the value alone can't be set to simply nil. (You could set it to NSNULL though).
So to answer your question, your code can't replace the existing.

Copy objects from NSArray to another NSArray

i'm making an iOS app using VKSdk.
I want to copy data from response.json[#"items"](it's nsarray,response.json its nsdictionary) to my nsarray.
Here is my code:
VKRequest * getWall = [VKRequest requestWithMethod:#"wall.get" andParameters:#{VK_API_OWNER_ID : #"1"} andHttpMethod:#"GET"];
[getWall executeWithResultBlock:^(VKResponse * response) {
_vk_array=[[NSArray alloc]initWithArray:response.json[#"items"]];
NSLog(#"%#",_vk_array);//shows null
NSLog(#"%#",response.json[#"items"]);//shows ok
} errorBlock:^(NSError * error) {
if (error.code != VK_API_ERROR) {
[error.vkError.request repeat];
}
else {
NSLog(#"VK error: %#", error);
}
}];
I also trying to use just this code
_vk_array=response.json[#"items"]
But it still shows "null". Am i doing something wrong?
PS:
NSLog(#"%hhd",([response.json[#"items"] isKindOfClass:[NSArray class]]));//shows 1
Hi you can use it to copy an array object into another array.
NSArray *copyArray = [NSArray arrayWithArray:yourArray];
Thanks
[response.json[#"items"
_vk_array=[[NSArray alloc]initWithArray:response.json[#"items"]];
NSLog(#"%#",_vk_feed);//shows null
here you are assigning value to _vk_array But you are tracing value of _vk_feed.
Also, [response.json[#"items" is incomplete.

Magical Record add object, different context error

I'm using Magical Record in my app, and want to add the functionality for a user to add a 'Note', which is a child of 'entry'.
I added this code:
[MagicalRecord saveWithBlock: ^(NSManagedObjectContext *localContext) {
Note *newNote = [Note MR_createInContext: localContext];
newNote.content = noteContent;
newNote.name = #"User Note";
[self.entry addNotesObject: newNote];
}
completion: ^(BOOL success, NSError *error) {
if (error != nil)
{
// show alert
}
else if (success)
{
[[self tableView] reloadData];
}
}];
The error I keep getting on the last line is "Illegal attempt to establish a relationship 'entry' between objects in different contexts"
I tried setting the context of both 'entry' and 'newNote' to 'localContext', but I still get the same error.
What am I missing?
self.entry was created in different context, so you can't access it from this one.
Instead of:
[self.entry addNotesObject: newNote];
you should first find self.entry object in localContext:
[[self.entry MR_inContext:localContext] addNotesObject: newNote];
You can find an explanation of using MagicalRecord in a concurrent environment at Performing Core Data operations on Threads. Though it's quite short, so in my opinion it's worthwhile to read Core Data Programming Guide even though you don't use CD directly.

How to print something so that if it is nil, it will print nil - iOS

I always use NSLog to print out contents of objects when I am debugging my iOS applications. But any time I come across a "nil" object, the program crashes. In Java, if an object is null, it will print "null". Is there a way to do this in Objective-C?
Something like:
if (questionableObject == nil) {
NSLog(#"questionableObject is nil.");
} else {
NSLog(#"questionableObject is: %#", questionableObject);
}
I've only really run into this problem when I send a message to an object inside the NSLog parameter list that uses a nil object as a parameter. Something like this:
if (questionableObject == nil) {
NSLog(#"questionableObject is nil.");
} else {
NSLog(#"result is: %#", [something someMessage:questionableObject]);
}
What do you mean by "print out contents of objects"? If you're dereferencing a nil pointer, that'll cause a problem. If you're just printing the pointer, that should be OK. You can also send messages to nil without problem, so you could do this:
NSLog(#"theObject is: %#", [theObject description]);

Resources