Page 1 of 1
"AssociatedObject" key through different variable
Posted: Tue Oct 11, 2022 10:22 am
by mestnyi
Code: Select all
ImportC ""
objc_setAssociatedObject( object, ; Any
key.s, ; UnsafeRawPointer,
value, ; Any?,
policy ) ; objc_AssociationPolicy
objc_getAssociatedObject( object, ; Any
key.s ) ; UnsafeRawPointer
EndImport
If OpenWindow(0, 0, 0, 300, 300, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
Define key.s = "___data"
Define key1.s = key ; "___data"
objc_setAssociatedObject_( WindowID(0), key, 12345, 0 )
Debug objc_getAssociatedObject_( WindowID(0), key1 )
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
Re: "AssociatedObject" key through different variable
Posted: Tue Oct 11, 2022 4:28 pm
by mestnyi
does anyone know why this is happening?
Re: "AssociatedObject" key through different variable
Posted: Tue Oct 11, 2022 6:23 pm
by fsw
Not sure why, but I found this:
https://nshipster.com/associated-objects/
And it says that the keys should be constants:
It is often recommended that they key be a static char—or better yet, the pointer to one. Basically, an arbitrary value that is guaranteed to be constant, unique, and scoped for use within getters and setters:
If the key is a variable and it is copied (as in your case) it is not unique anymore, is it?
The AssociatedObject functions uses the exact memory location (pointer) of the variable.
The proof is in the pudding:
Using constants instead of variables works even when a constant is copied:
and later using:
Code: Select all
Debug objc_getAssociatedObject_( WindowID(0), #key )
Debug objc_getAssociatedObject_( WindowID(0), #key2 )
Debug objc_getAssociatedObject_( WindowID(0), "___data" )
shows the same results.
#key and #key2 seem to hold the pointer to "___data" because the outputs are the same.
Strangely enough, the second literal string "___data" in the objc_getAssociatedObject_ function call works as well, even though the memory location should differ from the first literal string of "___data" (while defining #key = "___data").
Maybe the PB compiler is smart enough and compares literal strings with already used literal strings and if it finds the same literal string it uses the pointer of the original literal string, instead of storing the same literal string twice.
Interesting stuff...
Re: "AssociatedObject" key through different variable
Posted: Wed Oct 12, 2022 8:10 pm
by mestnyi
I wanted to use like this.
It didn't work, but what surprises me is if I add this line "AllocateStructure(String)" anywhere, it starts working.
or when I assign "key" to a structure like this "Protected *key.String = @key"
Code: Select all
AllocateStructure(String) ;1 uncomment to see work - why??????????
DeclareModule Associated
EnableExplicit
Declare Get( object.i, key.s )
Declare Remove( object.i, key.s )
Declare Set( object.i, key.s, value.i )
EndDeclareModule
Module Associated
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
#OBJC_ASSOCIATION_ASSIGN = 0
#OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1
#OBJC_ASSOCIATION_COPY_NONATOMIC = 3
#OBJC_ASSOCIATION_RETAIN = 769
#OBJC_ASSOCIATION_COPY = 771
CompilerEndIf
Procedure Get( object.i, key.s )
;Protected *key.String = @key ;2 uncomment to see work
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_MacOS
ProcedureReturn objc_getAssociatedObject_( object, key )
CompilerCase #PB_OS_Windows
ProcedureReturn GetProp_( object, key )
CompilerEndSelect
EndProcedure
Procedure Remove( object.i, key.s )
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_MacOS
objc_setAssociatedObject_( object, key, #Null, #OBJC_ASSOCIATION_ASSIGN )
; objc_removeAssociatedObjects_(object )
CompilerCase #PB_OS_Windows
RemoveProp_( object, key )
CompilerEndSelect
EndProcedure
Procedure Set( object.i, key.s, value.i )
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_MacOS
objc_setAssociatedObject_( object, key, value, #OBJC_ASSOCIATION_ASSIGN )
CompilerCase #PB_OS_Windows
SetProp_(object, key, value )
CompilerEndSelect
EndProcedure
EndModule
CompilerIf #PB_Compiler_IsMainFile
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
If OpenWindow(0, 0, 0, 300, 300, "Resize me !", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
Define key.s = "___data"
Define key1.s = key ; "___data"
;Define *key.String = @key1
; objc_setAssociatedObject_( WindowID(0), key, 12345, 0 )
; Debug objc_getAssociatedObject_( WindowID(0), key1 )
Associated::Set( WindowID(0), "___data", 12345)
Debug Associated::Get( WindowID(0), "___data")
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
CompilerEndIf
CompilerEndIf
Re: "AssociatedObject" key through different variable
Posted: Thu Oct 13, 2022 6:38 pm
by fsw
Something is goofy...
This works as well even though it shouldn't:
Code: Select all
Define key.s = "___data"
Define key1.s = key ; "___data"
Associated::Set( WindowID(0), "___data", 12345)
Debug Associated::Get( WindowID(0), "___data")
Debug Associated::Get( WindowID(0), key)
Debug Associated::Get( WindowID(0), key1)
Weird!
Even more weird:
Code: Select all
Define key.s = "___data"
Define key1.s = key ; "___data"
Associated::Set( WindowID(0), "___banana", 12345)
Debug Associated::Get( WindowID(0), key)
Debug Associated::Get( WindowID(0), key1)
Debug Associated::Get( WindowID(0), "___d")
Debug Associated::Get( WindowID(0), "___da")
Debug Associated::Get( WindowID(0), "___dat")
Debug Associated::Get( WindowID(0), "___data")

Re: "AssociatedObject" key through different variable
Posted: Fri Oct 14, 2022 5:03 pm
by mestnyi
amazing things really happen
Well at least it works.
Code: Select all
DeclareModule Associated
Declare Get( object.i, *key.String )
Declare Remove( object.i, *key.String )
Declare Set( object.i, *key.String, value.i )
EndDeclareModule
Module Associated
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
#OBJC_ASSOCIATION_ASSIGN = 0
#OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1
#OBJC_ASSOCIATION_COPY_NONATOMIC = 3
#OBJC_ASSOCIATION_RETAIN = 769
#OBJC_ASSOCIATION_COPY = 771
CompilerEndIf
Procedure Get( object.i, *key.String )
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_MacOS
ProcedureReturn objc_getAssociatedObject_( object, *key\s )
CompilerCase #PB_OS_Windows
ProcedureReturn GetProp_( object, *key\s )
CompilerEndSelect
EndProcedure
Procedure Remove( object.i, *key.String )
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_MacOS
objc_setAssociatedObject_( object, *key\s, #Null, #OBJC_ASSOCIATION_ASSIGN )
; objc_removeAssociatedObjects_(object )
CompilerCase #PB_OS_Windows
RemoveProp_( object, *key\s )
CompilerEndSelect
EndProcedure
Procedure Set( object.i, *key.String, value.i )
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_MacOS
objc_setAssociatedObject_( object, *key\s, value, #OBJC_ASSOCIATION_ASSIGN )
CompilerCase #PB_OS_Windows
SetProp_(object, *key\s, value )
CompilerEndSelect
EndProcedure
EndModule
CompilerIf #PB_Compiler_IsMainFile
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
If OpenWindow(0, 0, 0, 300, 300, "Resize me !", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
; Define key.s = "___data"
; Define key1.s = key ; "___data"
;
; ; objc_setAssociatedObject_( WindowID(0), key, 12345, 0 )
; ; Debug objc_getAssociatedObject_( WindowID(0), key1 )
;
; Associated::Set( WindowID(0), @"___data", 12345)
; Debug Associated::Get( WindowID(0), @"___data")
; Associated::Remove( WindowID(0), @"___data")
; Debug Associated::Get( WindowID(0), @"___data")
Define key.s = "___data"
Define key1.s = key ; "___data"
Associated::Set( WindowID(0), @"___banana", 12345)
Debug Associated::Get( WindowID(0), @key)
Debug Associated::Get( WindowID(0), @key1)
Debug Associated::Get( WindowID(0), @"___d")
Debug Associated::Get( WindowID(0), @"___da")
Debug Associated::Get( WindowID(0), @"___dat")
Debug Associated::Get( WindowID(0), @"___data")
Debug Associated::Get( WindowID(0), @"___banana")
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
CompilerEndIf
CompilerEndIf
Re: "AssociatedObject" key through different variable
Posted: Fri Oct 14, 2022 5:11 pm
by mestnyi
no, that doesn't work either.
it turns out the key should not be longer than 4 characters
Code: Select all
Associated::Set( WindowID(0), @"___data", 12345)
Associated::Set( WindowID(0), @"___data2", 54321)
Debug Associated::Get( WindowID(0), @"___data")
Debug Associated::Get( WindowID(0), @"___data2")
Re: "AssociatedObject" key through different variable
Posted: Fri Oct 14, 2022 5:28 pm
by mestnyi
he did not need a line
Code: Select all
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
If OpenWindow(0, 0, 0, 300, 300, "Resize me !", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
Define key3 = 1234566788
Define key4 = key3
objc_setAssociatedObject_( WindowID(0), 123456789, 12345, 0 )
Debug objc_getAssociatedObject_( WindowID(0), 123456789 )
objc_setAssociatedObject_( WindowID(0), key3, 12345, 0 )
Debug objc_getAssociatedObject_( WindowID(0), key4 )
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
CompilerEndIf
Re: "AssociatedObject" key through different variable
Posted: Sat Oct 15, 2022 10:27 am
by mk-soft
Why not use maps ...
Update
- Bugfix
Code: Select all
DeclareModule Associated
Declare Get( object.i, key.s )
Declare Set( object.i, key.s, value.i )
Declare Remove( object.i, key.s )
Declare Release( object.i )
EndDeclareModule
Module Associated
Structure udtAssociatedObject
Map key.i()
EndStructure
Global NewMap mapAssociatedObject.udtAssociatedObject()
Procedure Get( object.i, key.s )
If FindMapElement(mapAssociatedObject(), Str(object))
If FindMapElement(mapAssociatedObject()\key(), key)
ProcedureReturn mapAssociatedObject()\key()
EndIf
EndIf
EndProcedure
Procedure Set( object.i, key.s, value.i )
If Not FindMapElement(mapAssociatedObject(), Str(object))
AddMapElement(mapAssociatedObject(), Str( object))
EndIf
If AddMapElement(mapAssociatedObject()\key(), key)
mapAssociatedObject()\key() = value
ProcedureReturn #True
EndIf
ProcedureReturn #False
EndProcedure
Procedure Remove( object.i, key.s )
If FindMapElement(mapAssociatedObject(), Str(object))
If FindMapElement(mapAssociatedObject()\key(), key)
DeleteMapElement(mapAssociatedObject()\key())
EndIf
EndIf
EndProcedure
Procedure Release( object.i )
If FindMapElement(mapAssociatedObject(), Str(object))
DeleteMapElement(mapAssociatedObject())
EndIf
EndProcedure
EndModule
CompilerIf #PB_Compiler_IsMainFile
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
If OpenWindow(0, 0, 0, 300, 300, "Resize me !", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_SizeGadget)
Define key.s = "___data"
Define key1.s = key ; "___data"
Associated::Set( WindowID(0), "___banana", 12345)
Associated::Set( WindowID(0), key1, 100)
Debug Associated::Get( WindowID(0), key)
Debug Associated::Get( WindowID(0), key1)
Debug Associated::Get( WindowID(0), "___d")
Debug Associated::Get( WindowID(0), "___da")
Debug Associated::Get( WindowID(0), "___dat")
Debug Associated::Get( WindowID(0), "___data")
Debug Associated::Get( WindowID(0), "___banana")
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
EndIf
CompilerEndIf
CompilerEndIf
Re: "AssociatedObject" key through different variable
Posted: Sun Oct 16, 2022 7:24 pm
by mestnyi
mk-soft wrote: Sat Oct 15, 2022 10:27 am
Why not use maps ...
I thought it would be better and more reliable
And the memory will be less.
Re: "AssociatedObject" key through different variable
Posted: Sun Oct 16, 2022 9:54 pm
by fsw
@mk-soft:
This is the output on my M1 Mac:
100
100
0
0
0
100
0
but it should be:
100
100
0
0
0
100
12345
@mestnyi
Further testing with your first code shows that it works perfectly as long as real constants or literal strings are used.
Re: "AssociatedObject" key through different variable
Posted: Sun Oct 16, 2022 11:27 pm
by mk-soft