As I studied the issue I am facing in Trying to create NSDecimal in iPhone-Wax I am now aiming much lower. How can I create a fully functional NSDecimalNumber in Wax?
I have added the following two lines at the top of AppDelegate.lua in a fresh wax project.
local x = NSDecimalNumber:initWithString("2.3")
print(x)
print(x:class())
The output is
(0x631e054 => 0x631d1a0) 2.3
(0x631e924 => 0x25f618) NSCFNumber
instead of something like
(0x621e834 => 0x620c550) <NSDecimalNumber: 0x620c550>
Turning on full logging in wax give the following trace in the debug window:
Creating class for WaxServer(0x621bf40)
Storing reference of class to userdata table WaxServer(0x621bf40 -> 0x621c454)
Storing reference to strong userdata table WaxServer(0x621bf40 -> 0x621c454)
Creating class for NSDecimalNumber(0x261120)
Storing reference of class to userdata table NSDecimalNumber(0x261120 -> 0x6205e44)
Storing reference to strong userdata table NSDecimalNumber(0x261120 -> 0x6205e44)
Creating instance for NSDecimalNumberPlaceholder(0x6213450)
Retaining instance for NSDecimalNumberPlaceholder(0x6213450 -> 0x621d7c4)
Storing reference of instance to userdata table NSDecimalNumberPlaceholder(0x6213450 -> 0x621d7c4)
Storing reference to strong userdata table NSDecimalNumberPlaceholder(0x6213450 -> 0x621d7c4)
Creating instance for NSCFNumber(0x620c550)
Retaining instance for NSCFNumber(0x620c550 -> 0x621e834)
Storing reference of instance to userdata table NSCFNumber(0x620c550 -> 0x621e834)
Storing reference to strong userdata table NSCFNumber(0x620c550 -> 0x621e834)
(0x621e834 => 0x620c550) 2.3
Creating class for AppDelegate(0x621ec50)
:
:
Two things are showing in this log which I did not ask for, NSDecimalNumberPlaceholder and NSCFNumber. I believe these are the source of my grief and I have no idea where they are coming from. Any ideas on how to fix the issue?
Ultimately I want to call the method decimalValue, but wax complains that it can't call a method on a number.
NSDecimalNumber overrides -description to return the number it represents. When you're logging statement is printing "2.3", it is in fact printing the NSDecimalNumber object. You can verify this for yourself by calling -class on your x value and printing that as well.
Related
I am working in a iOS project involving Realm and the use of Generics. I am exploring ways to clone a retrieved Realm object to update it outside a write transaction and then send it to an update function using generics.
I am facing a weird problem and i don't know if it is related to Realm or to the Generics stuff. You help will be appreciated
Setting:
One class GenericObject that inherits from Realm Object, and a subclass called Sale:
GenericObject: Object
Sale: Generic Object // This class includes a primary key called "id"
I fetch a Sale object from the web and I am able to save it in Realm, creating a new object outside the write transaction (I could save it without worrying about the write transaction, but I want to use the same code and flow for any update)
When I modify a property of the object and try to update Realm, it throws an exception because the primary key can't be found. (The primaryKey is defined in the subclass Sale)
I have been able to pinpoint the problem to my newItem() method in Sale as follows:
override func newItem<T:GenericObject>(ofType itemType: T.Type) -> T {
let dictionary = self.getDictionary()
let newItem = T.init()
newItem.updateWithDictionary(dict: dictionary)
print("Type: \(type(of: newItem)) - Object: \(newItem)")
return newItem
}
And then, I call it as follows:
let newObject = object.newItem(ofType: Sale.self)
self.realm.add(newObject, update: true)
So far, so good. I retrieve the object from the web and it works. The print() reports that type(of:) the instantiate object is Sale, and the printout of the object also says Sale
Type: Sale - Object: Sale { ....
When I update the object and save it, it fails saying that Realm could not find the primary key, type(of:) reports Sale, but the instance is printed as the GenericObject superclass, as follows:
Type: Sale - Object: GenericObject { ....
This result is running the same code and the same code execution. I am using Xcode 10 and Swift 4.2, with Realm 3
Any idea what may be happening here?
After 6 months, the problem seems to be fixed without a clear indication of what was going on.
As of 2019-04-22, having migrated to Realm 3.14.1, Xcode 10.2.1 and Swift 5.0, I am able to get a clone of the object using T.init(), and saving it successfully outside the Realm write transaction with the original code used when I posted the question
I don't see anything related to a syntax change from Swift 4.2 to 5.0, but I understand that Xcode 10.2.1 includes updates to LLVM/clang.
I'd love to spend some time checking the new compiler with the previous Realm version
I was trying to follow instructions from Learning Swift book (creating note taking app) by B.A. Paris & Co, but faced with the following problem with binding. I am mostly practicing iOS programming, so binding concept is new for me.
Steps I made (tried both xcode 9 beta 5 and 8.3.3):
Create OSX Cocoa App (not using storyboard, document based app – on, document
extension “test”, don’t use core data)
Add “var text = NSAttributedString()” to Document.swift
Add a NSTextView to Document.xib
In Bindings inspector of NSTextView setting “Attributed String” to File’s owner “self.text” (Model Key Path)
And I see exclamation mark with notion “Xcode cannot resolve the entered key path”
Build is successful, but when I run it says “2017-09-03 22:17:40.739643+0200 test3[6017:424072] [<test3.Document 0x6180000c3410> valueForUndefinedKey:]: this class is not key value coding-compliant for the key text.”
I tried to control drag from Xib to Swift, it warns that “Xcode cannot locate the class Document in the current workspace”.
I tried to convert to workspace instead of proj, checked the file owner, checked the stackoverflow threads witch relate to the error – but they mostly concerned about some connection made by mistake or non actual connections (I can delete the connection, I know what connection is wrong, the question is how to make it right). So far could not find solution.
Thanks in advance
You need to declare the text property with the #objc attribute to make it accessible via dynamic dispatch like Key-Value Coding.
Also, because you want modifications of the property to be observable via Key-Value Observing (for Bindings), you need to tell Swift to always dispatch modifications of it dynamically. So, you need to use the dynamic modifier on the declaration, too:
#objc dynamic var text = NSAttributedString()
I have an Objective-C model class MyType. This class is used in Swift code:
NSEntityDescription.insertNewObjectForEntityForName("MyType", inManagedObjectContext: context) as! MyType
The as! cast results in the error message
Core Data: Could not cast value of type 'MyType_MyType_2' (0x7be99a30) to MyType (0xf33db74).
If I cast it as NSManagedObject it works. When I print the result, I can nevertheless see, that it is an actual instance of MyType:
<MyType: 0x7ae06d50> (entity: MyType; id: 0x7aeba6d0 <x-coredata:///MyType/t957F2860-85F8-46E0-B6D6-4D1DF6C4EC613> ; data: {
...the fields...
})
What is happening here? And where does the name MyType_MyType_2 come from?
When I had this issue, it was because I had forgotten to set the "class" on the entity. This is what I came up with:
Click on .xcdatamodelId file in your file structure/project
navigator pane (far left).
Select the entity that you are having issues with.
In the Utilities pane (far right), look for the icon that looks like a 1997 cell phone, the Data Model Inspector.
Under the entity settings, you should see two fields, "Name" and "Class" - set up "Class" with the name of the class you are using (typically the same as "Name").
You'll even notice before you follow these steps that the default "class" is NSObject, reflecting the error message. I found some programatic ways to do this too, but this seemed like the simplest/quickest solution.
I should note that my model WAS written in Swift, so I did have to add the #objc(Entity) interoperability reference mentioned by #zellb. But that shouldn't make a difference in the solution as long as you are doing that part properly (and that would cause a different unrelated error from my understanding).
Set Entity Class Name
Set Module "Current Product Module" like below
just try this:
#objc(MyType)
public class MyType: NSManagedObject {
// your class
}
instead of this:
class MyType: NSManagedObject {
// your class
}
I had mistakenly set a "parent entity" in one of my entities in the data model inspector in the entity section. I mistakenly thought that referred to the destination of a one-to-many relationship.
Setting it back to "no parent entity" fixed the problem, although I did have to delete and reinstall the app in the simulator to deal with the messed up core data database.
I have a problem with Lua and I don't know if I going in the right direction. In C++ I have a dictionary that I use to pass parameter to a resource manager. This dictionary is really similar to a map of hash and string.
In Lua I want to access to these resource so I need a representation of hashes. Also hashes must be unique cause are used as index in a table. Our hash function is 64bit and I'm working on 32bit enviroment (PS3).
C++ I have somethings like that:
paramMap.insert(std::make_pair(hash64("vehicleId"), std::string("004")));
resourceManager.createResource(ResourceType("Car"), paramMap);
In Lua want use these resources to create a factory for other userdata.
I do stuff like:
function findBike(carId)
bikeParam = { vehicleId = carId }
return ResourceManager.findResource('car', bikeParam)
end
So, sometime parameter are created by Lua, sometime parameter are created by C++.
Cause my hashkey ('vehicleId') is an index of a table it need to be unique.
I have used lightuserdata to implement uint64_t, but cause I'm in a 32bit enviroment I can't simply store int64 in pointer. :(
I have to create a table to store all int64 used by the program and save a reference in userdata.
void pushUInt64(lua_State *L, GEM::GUInt64 v)
{
Int64Ref::Handle handle = Int64Ref::getInstance().allocateSlot(v);
lua_pushlightuserdata(L, reinterpret_cast<void*>(handle));
luaL_setmetatable(L, s_UInt64LuaName);
}
but userdata are never garbage collected. Then my int64 are never released and my table will grow forever.
Also lightuserdata don't keep reference to metadata so they interfere with other light userdata. Checking the implementation the metadata table is added in L->G_->mt_[2].
doing that
a = createLightUserDataType1()
b = createLightUserDataType2()
a:someFunction()
will use the metatable of b.
I thought that metatable where bounded to type.
I'm pretty confused, with the current implementation lightuserdata have a really limited use case.
With Python you have a hash metafunction that is called anytime the type is used as index for a dictionary. It's possible to do something similar?
Sorry for my english, I'm from Italy. :-/
In my project I have some objects that I show from a server, lets call them Foo's. When I get my Foo feed, I parse them into a NSMutableDictionary subclass called RemoteFoo, and pass these RemoteFoo objects all around the app to display data.
If the user ends up wanting to download a RemoteFoo, I then create a core-data NSManagedObject entity called Foo, and instantiate it using the values from the RemoteFoo. All this works.
The problem I have is that If I want a method to run on a RemoteFoo and a Foo, I have to duplicate it in both RemoteFoo.m and Foo.m. Also, my app if full of duplicate init's like:
- (id)initWithFoo:(Foo *)foo;
- (id)initWithRemoteFoo:(RemoteFoo *)foo;
How can I avoid all of this code-duplication while still separating the temporary remote RemoteFoo from the core-data Foo entities that represent the Foo the user has saved locally?
Have you thought of using something like a class cluster -
http://seanmurph.com/weblog/make-your-own-abstract-factory-class-cluster-in-objective-c/
--------- Foo -------- NSManagedObject
| | |
RemoteFoo LocalFoo ------ CoreDataFoo
You could just save all RemoteFoo's as Foo's and work with those. If you need different behavior, you could have an attribute on Foo indicating if it's remote or not.
Change your Core Data model as follow. Use one Foo instance and add a boolean attribute isRemote (or something similar) that you set by default to NO. When you download your remote objects, instantiate those as Foo managed objects and set their isRemote attribute to yes.
This way, you only need to deal with one instance in your app, while retaining the ability to clearly differentiate between local and remote Foo objects. If your app allows this you may even declare the isRemote attribute as transient, so that it will never be stored on disk, just in memory. If you do no care to persist this information, then this may be the best way to go.