How do I handle float in Core Data / iPhone? - core-data

I recently got started on Core Data, thanks to this tutorial :
http://www.techotopia.com/index.php/An_iPhone_OS_Core_Data_Tutorial
My question is about handling types other than String.
For example let us say I want to add to the existing fields (name,address and phone : which are all String(s) in the example presented), the weight which I want to be a float in my entity.
How would I change the code to handle a float instead of a String ?
I already tried to change one of the fields to float in my entity. First letting the code as it is, and the program crashed. Then I tried to adjust the code in some ways but it did not work. I have the feeling it must be simple, but I can't get it right.
Thanks for any tip.

you should use NSNumber for float (and access it with [myNumber floatValue]).
You can't use primitive values in CoreData entities - only objects. ( NSString, NSDate, NSNumber, NSData ... )
Hope this helps.

Related

NSFetchedResultsController + UICollectionViewDiffableDataSource + CoreData - How to diff on the entire object?

I'm trying to use some of the new diffing classes built into iOS 13 along with Core Data. The problem I am running into is that controllerdidChangeContentWith doesn't work as expected. It passes me a snapshot reference, which is a reference to a
NSDiffableDataSourceSnapshot<Section, NSManagedObjectID>
meaning I get a list of sections/Object ID's that have changed.
This part works wonderfully. But the problem comes when you get to the diffing in the collection view. In the WWDC video they happily call
dataSource.apply(snapshot, animatingDifferences: true)
and everything works magically, but that is not the case in the actual API.
In my initial attempt, I tried this:
resolvedSnapshot.appendItems(snapshot.itemIdentifiersInSection(withIdentifier: section).map {
controller.managedObjectContext.object(with: $0 as! NSManagedObjectID) as! Activity
}, toSection: .all)
And this works for populating the cells, but if data is changed on a cell (IE. the cell title) the specific cell is never reloaded. I took a look at the snapshot and it appears the issue is simply that I have references to these activity objects, so they are both getting updated simultaneously (Meaning the activity in the old snapshot is equivalent to the one in the new snapshot, so the hashes are equal.)
My current solution is using a struct that contains all my Activity class variables, but that disconnects it from CoreData. So my data source became:
var dataSource: UICollectionViewDiffableDataSource<Section, ActivityStruct>
That way the snapshot actually gets two different values, because it has two different objects to compare. This works, but it seems far from elegant, is this how we were meant to use this? Or is it just in a broken state right now? The WWDC video seems to imply it shouldn't require all this extra boilerplate.
I ran into the same issue and I think I figured out what works:
There are two classes: UICollectionViewDiffableDataSource and UICollectionViewDiffableDataSourceReference
From what I can tell, when you use the first, you're taking ownership as the "Source of Truth" so you create an object that acts as the data source. When you use the second (the data source reference), you defer the "Source of Truth" to another data source (in this case, CoreData).
You would instantiate a ...DataSourceReference essentially the same way as a ...DataSource:
dataSourceReference = UICollectionViewDiffableDataSourceReference(collectionView: collectionView, cellProvider: { (collectionView, indexPath, object) -> UICollectionViewCell? in
let identifier = <#cell identifier#>
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
<#cell configuration#>
return cell
})
And then later when you implement the NSFetchedResultsControllerDelegate, you can use the following method:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference)
{
dataSourceReference.applySnapshot(snapshot, animatingDifferences: true)
}
I watched the WWDC video as well and didn't see this referenced. Had to make a few mistakes to get here. I hope it works for you!

How do I add int field into ListView?

So I'm trying to fill a table, which is made by using ListView. "a" is some int, and obviously I can not just add an item like this, cuz it asks for string^. How do I convert my int to this string^? And what's the difference between usual string and string^?
System::Windows::Forms::ListViewItem^ listView1Item;
private: System::Windows::Forms::ListView^ listView1;
...
listView1Item = gcnew Windows::Forms::ListViewItem(a);
listView1->Items->Add(listView1Item);
To convert int a to a string, call a.ToString(). ToString is defined on the .Net base class Object, so just about everything has a ToString you can call. (Since you're in C++/CLI, things that are purely unmanaged will not have a ToString method. But anything that's managed, or primitives that are also used in .Net (e.g., int), will.)
As for the difference between String and String^, I'm not sure exactly what you mean by the "usual string". I'm not sure whether you're referring to C++'s std::string, or to .Net's System::String, just without the ^. String^ refers to the .Net System::String class, as a manged reference. Managed references are roughly equivalent to unmanaged pointers, but the garbage collector is allowed to move things around as it does its work, and the managed reference continues to point at the proper object.
The answer was:
System::Convert::ToString()
Thx everybody for help =)

CFBitVector stored as an attribute to a coredata object

I am attempting to create a fingerprint for an object in coreData, and want to set it as attribute to an object. I figured CFBitArray is the way to go.
I am trying to figure out how to save this per object:
Here is an example
Object
attributes:
Name:
Fingerprint ("01010101010101010101010110") etc...
This is used to try to match with a master print
Any suggestions?
You'd have to convert that to/from something Core Data understands, and save the converted value. There are a couple of possibilities, both of which involve getting the actual bits via CFBitVectorGetBits. Once you have that, you can
Save them in an NSData using something like +dataWithBytes:length:, and put that in a binary-type attribute on a managed object. Or...
Depending on the number of bytes you're using, save them in an NSNumber using something like +numberWithLong: (or whatever is long enough for the number of bits). Then put that in one of Core Data's integer types-- again, choosing whatever size fits your bits.
You can make the conversion either by using custom accessor methods on your NSManagedObject subclass, or by using the transformable Core Data attribute type and a value transformer class. For the latter you'd subclass NSValueTransformer and implement your conversions there (Apple provides a couple of examples of this).
Depending on what you're actually doing, you might want to consider using NSIndexSet instead of CFBitVectorRef. If nothing else, it conforms to NSCoding-- which means you can use a transformable attribute but rely on Core Data's default value transformer instead of writing your own.
You might also find it a lot simpler to just use one of the integer types and rely on bitwise operators to determine if a bit is set. Then you don't need to do anything special with Core Data, you just choose the appropriately-sized integer type.
Why are you not just storing NSData? It is way, way easier to store binary data inside NSData than inside CFBitvectorRef.
If you're trying to store a hash / fingerprint of something, I assume you're creating a SHA-256 hash with CC_SHA256_Init, _Update and _Final. Those will give you a so-called digest which is a fingerprint of the data you pass into the CC_SHA256_Update.
// Create the context:
CC_SHA256_CTX shaContext;
CC_SHA256_Init(&shaContext);
// For each value:
CC_SHA256_Update(&shaContext, &v, sizeof(v));
// Get the fingerprint / digest:
unsigned char digest[CC_SHA256_DIGEST_LENGTH];
CC_SHA256_Final(digest, &shaContext);
NSData *fingerprint = [NSData dataWithBytes:digest length:sizeof(digest)];
Then you can store that fingerprint into a Core Data attribute that's Binary Data.
Depending on the type of v, you might have to change the call to CC_SHA256_Update(). If you do this on an NSObject, you need to call it for each instance variable that you're interested in (that should be part of the fingerprint), e.g. if you have
#property (nonatomic) int32_t count;
#property (nonatomic, copy) NSString *name;
you'd do
int32_t v = self.count
CC_SHA256_Update(&shaContext, &v, sizeof(v));
NSData *d = [self.name dataUsingEncoding:NSUTF8Stringencoding];
CC_SHA256_Update(&shaContext, [data bytes], [data length]);

How can I know the class type of an abstract entity in a NSPredicate?

Using core data I'd like to fetch some data. My model uses some abstract entities, see attached picture, where QuantifiedIngredient is an abstract class.
I'd like to fetch Ingredient entities that have at least one RecipeQuantifiedIngredients, but in the middle is QuantifiedIngredient, which is an abstract class.
How can I do that, how can I test the actual type of an abstract class inside a NSPredicate? Any idea or suggestion?
The only clue I found was:
How can you reference child entity name in a predicate for a fetch request of the parent entity?
Would work a custom property in my QuantifiedIngredient to know if it is a RecipeQuantifiedIngredient? For instance isRecipeQuantifiedIngredient?
Thanks a lot for your help.
If recipe is required in RecipeQuantifiedIngredient, you could try to make a fetch, that checks, if there is any ingredient.recipe. I think, that will work.
The custom property, in kind of flag, will work for you too. You'll just need to set and unset it whenever you add or delete all the recipeQuantifiedIngredient.
I don't want to take the time to translate this into CoreData-speak so here is my thought in SQL:
SELECT * FROM quantifiedIngredients WHERE recipe <> NULL
or something like that. This is essentially Nikita's suggestion of using a flag, except that the 'flag' is the existence of a property. I don't know how CoreData will react when faced with GroceryQuantifiedIngredients that don't have the recipe, I think KVO will throw an exception. You might be so bold as to add a category:
#interface GroceryQuantifiedIngredients (KVOHack)
-(id)recipe;
#end
#implementation GroceryQuantifiedIngredients (KVOHack)
-(id) recipe { return nil; }
#end
This would of course require CoreData to enumerate all quantifiedIngredients, but I presume it will have to do so anyway, and a the return nil should optimize into tiny code. The other consideration is whether this will have a bad effect on the rest of your code; you will have to make that call.
Another idea which pops to mind as I finish this up is to do something like this (I'm getting really loose with my pseudo-code now):
SELECT * FROM quantifiedIngredients WHERE [i respondsToSelector:#selector(recipe)];
See what I mean? I forget whether CoreData lets you play with some kind of cursor when working with predicates or fetchedThingamabobbers, if it does than I think this is your best bet. Anyway it's Sunday afternoon so that stuff is left as a exercise for the reader.
+1 for a good question.

ios detachNewThreadSelector, how to withObjects?

I know that
detachNewThreadSelector:toTarget:withObject
can have a (id)anArgument. I have searched it that it can work for NSString.
However, when I pass an integer or size_t, it crashed. Can somebody tell me what is (id)anArgument?
What's more, how can I pass more than one parameter to the thread? For example, I have a function,
-(NSInteger)getIneger: (NSInteger) pageNumber withName(NSString*) filename ;
something like that.
Thanks
What (id)anArgument tells you is that you need to pass an Objective-C argument. Since neither integer nor size_t are Objective-C objects, the application crashes. You will need to package them within an NSNumber for this to work. You will also have to alter the method to take in an NSNumber rather than the int. To pass two or more arguments, I suggest you use an NSDictionary object to pass values based on keys. You can define a method that takes in an NSDictionary object, unpacks the values and calls the original method you had intended to call.

Resources