Closed programmingkidx closed 11 months ago
So far I haven't come across too many APIs that take an NSArray that will be written to, but I suspect that pattern is not working here because of the copying going on for converting from slices. If you were to use objc.Call
to call InstantiateWithOwnerTopLevelObjects
passing a constructed NSArray (maybe foundation.Array_Array()
) it might work and I could look into how we might handle that in generated bindings.
Your suggestion worked! I saw the correct output for the first time.
Here is the updated program with your suggestion implemented:
// File: main.go
// Date: 11/29/23
// Description: Uses a NIB file to display the interface
// Run directions: go run main.go
package main
import (
"fmt"
"os"
"github.com/progrium/macdriver/macos/appkit"
f "github.com/progrium/macdriver/macos/foundation"
"github.com/progrium/macdriver/objc"
)
func main() {
// Setup the application
app := appkit.Application_SharedApplication()
app.SetActivationPolicy(appkit.ApplicationActivationPolicyRegular)
app.ActivateIgnoringOtherApps(true)
// Get the NIB file's data
godata, err := os.ReadFile("MainMenu.nib")
if err != nil {
fmt.Println("Failed to load nib file:", err)
return
}
fmt.Println("godata length:", len(godata))
// How the Nib would be obtained in Objective-C.
// Can't use this method because InstantiateWithOwnerTopLevelObjects
// does not accept (NS)Data object.
nsdata := f.Data_DataWithContentsOfFile("MainMenu.nib")
fmt.Println("nsdata length:", nsdata.Length())
myNib := appkit.NewNibWithNibDataBundle(godata, nil)
myObjects := f.Array_Array()
fmt.Printf("address of myObjects before: %p\n", &myObjects)
//status := myNib.InstantiateWithOwnerTopLevelObjects(nil, myObjects)
status := objc.Call[bool](myNib, objc.Sel("instantiateWithOwner:topLevelObjects:"), nil, &myObjects)
if status == false {
fmt.Println("Error: failed to instantiate nib file")
return
}
fmt.Printf("address of myObjects after: %p\n", &myObjects)
fmt.Println("successful NIB instantiation:", status)
fmt.Println("count:", myObjects.Count())
// print out all the objects found in the NIB file
var i uint
for i = 0; i < myObjects.Count(); i++ {
fmt.Printf("Index %d: %s\n", i, myObjects.ObjectAtIndex(i).Description())
}
}
I do still like the idea of using a Go slice in place of a (NS)Array type. It more Go-friendly.
Yes that would be nice. I'm not even sure it's possible here. We convert/copy the Go slice to an NSArray and then because it's just passed by reference we have no way to know when to convert/copy it back to our slice, which we would have to keep track of and further complicate an already tricky memory management situation.
Glad it worked!
Could we leave this issue open until the fix is in the repo?
What solution would make you want to close it?
I think adding the rule to the bindings generator that prevents translating from an Objective-c type to a Go type when dealing with a pointer to a pointer in a parameter would fix the problem. One reason to use a pointer to a pointer is to return an object thru a parameter like an NSError.
Here are some of the methods that are probably affected by this issue:
That is a great suggestion that I think should work well but can we make it a separate issue?
I think that is a good idea. This issue probably affects more than just NSNib's InstantiateWithOwnerTopLevelObjects().
Created issue https://github.com/progrium/macdriver/issues/234 for the generator issue.
I am trying to port this Objective-c program to Go. What is does is loads a NIB file and uses it to display the interface. To run this program copy and paste it to a file called main.m, then run this command: clear ; clang -framework foundation -framework appkit main.m && ./a.out Download the included MainMenu.nib.zip file is included here, unzip it, and place the MenuMenu.nib file in the same folder as the a.out program. MainMenu.nib.zip
This is most of the Go version of the above program:
This Go program should do the same things as the Objective-c version. The issue appears to be that Nib's InstantiateWithOwnerTopLevelObjects() does not return the objects in the slice that is used as an argument to the method. I believe this could be a bug with DarwinKit.
Here is the output for the Objective-c program:
Here is the output of the Go program:
The Go program does correctly display the length of the NIB file. But it returns zero objects in the slice.