Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macdriver: add NSUserDefaults bindings #118

Merged
merged 1 commit into from
Jul 4, 2023

Conversation

tmc
Copy link
Collaborator

@tmc tmc commented Jul 3, 2023

This is the result of:

  1. running macschema pull foundation/nsuserdefaults
  2. editing ./gen/cmd/gen.go
  3. running go run ./gen/cmd
  4. adding core/NSUserDefaults.go
  5. adding an example

fixes #115

@tmc tmc requested review from progrium and mgood July 3, 2023 22:36
@progrium progrium merged commit dd7dd17 into progrium:main Jul 4, 2023
@programmingkidx
Copy link
Contributor

programmingkidx commented Jul 4, 2023

I tried to do what you did but Macschema doesn't work for me. It always gives me this output:
=> Fetching sub-topics...
=> Waiting for workers to finish...
=> Generating schema...
2023/07/03 22:23:47 schema not supported for

Which version of Macschema are you using?
I am using version 0.2.0.

@progrium
Copy link
Owner

progrium commented Jul 4, 2023

Don't use the release. It's actively being developed and updated so you have to build from main until things settle for a new release.

@programmingkidx
Copy link
Contributor

@tmc Thank you very much for your help. Admittedly I was a little disappointed. I was making my own implementation of NSUserDefaults. This is how far I was:

package main

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -lobjc -framework Foundation

#include <Foundation/Foundation.h>
 
void *NSUserDefaults_standardUserDefaults()
{
	return [NSUserDefaults standardUserDefaults];
}
 
void setInteger_ForKey(void *ud, long value, char *defaultName)
{
	NSUserDefaults *theUD = (NSUserDefaults *)ud;
	NSString *keyStr = [NSString stringWithCString: defaultName];
	[theUD setInteger: value forKey: keyStr];
}
 
long integerForKey(void *ud, char *key)
{
	NSUserDefaults *theUD = (NSUserDefaults *)ud;
	NSString *keyStr = [NSString stringWithCString: key];
	return [theUD integerForKey: keyStr];
}
 
void setObject_ForKey(void *ud, char *cValue, char *cDefaultName)
{
	NSUserDefaults *theUD = (NSUserDefaults *)ud;
	NSString *value = [NSString stringWithCString: cValue];
	NSString *key = [NSString stringWithCString: cDefaultName];
	[theUD setObject: value forKey: key];
}
 
char *objectForKey(void *ud, char *defaultName)
{
	NSUserDefaults *theUD = (NSUserDefaults *)ud;
	NSString *key = [NSString stringWithCString: defaultName];
	NSString *returnStr = [theUD objectForKey: key]; //return value guaranteed to be a NSString
	return (char *)[returnStr cString];
 }
 
char *stringForKey(void *p, char *key)
{
	NSUserDefaults *theUD = (NSUserDefaults *)p;
	NSString *objcKey = [NSString stringWithCString: key];
	NSString *objcString = [theUD stringForKey: objcKey];
	return [objcString cString];
}

*/
import "C"
import "unsafe"
import "encoding/json"
//import "fmt"

type NSUserDefaults struct {
	objcObject unsafe.Pointer
}

func NSUserDefaults_standardUserDefaults() NSUserDefaults {
	p := unsafe.Pointer(C.NSUserDefaults_standardUserDefaults())
	userDefaults := NSUserDefaults{p}
	return userDefaults
}

func (ud *NSUserDefaults) SetInteger_ForKey(value int, defaultName string) {
	defaultNameCStr := C.CString(defaultName)
	cNumber := C.long(value)
	C.setInteger_ForKey(ud.objcObject, cNumber, defaultNameCStr)
}

func (ud NSUserDefaults) IntegerForKey(key string) int {
	p := ud.objcObject
	keyCStr := C.CString(key)
	value := C.integerForKey(p, keyCStr)
	goValue := int(value)
	return goValue
}

func (ud *NSUserDefaults) SetObjectForKey(value interface{}, defaultName string) {
	p := ud.objcObject
	strValue, err := json.Marshal(value) // Converts any Go type into a string for easier conversion to Objective-C
	if err != nil {
		panic(err)
	}
	cValue := C.CString(string(strValue))
	cDefaultName := C.CString(defaultName)
	C.setObject_ForKey(p, cValue, cDefaultName)
}


func (ud NSUserDefaults) ObjectForKey(defaultName string) []byte {
	p := ud.objcObject
	cDefaultName := C.CString(defaultName)
	cValue := C.objectForKey(p, cDefaultName)
	goStrValue := C.GoString(cValue)
	return []byte(goStrValue)
}

func (ud NSUserDefaults) StringForKey(key string) string {
	p := ud.objcObject
	cKey := C.CString(key)
	value := C.stringForKey(p, cKey)
	goValue := C.GoString(value)
	goValue = goValue[1:len(goValue)-1] // remove surrounding double-quotes
	return goValue
}

The main.go file I made for testing:

package main

import "fmt"
import "encoding/json"

func main() {
	// Get the object
	ud := NSUserDefaults_standardUserDefaults()
	
	// Set Value1 to 99
	ud.SetInteger_ForKey(99, "Value1")
	
	// Retrieve the value to see if it was stored correctly
	value1 := ud.IntegerForKey("Value1")
	
	// Run the test
	if value1 == 99 {
		fmt.Println("Test 1 Pass")
	} else {
		fmt.Println("Test 1 Fail")
	}
	
	// Create a Go structure
	type Computer struct {
		Model string
		RamSize int
		CPU string
		Manufacturer string
	}
	
	// Create an instance of Computer
	macbook := Computer{"MacBook Air", 16, "M1", "Apple"}
	
	// Make sure it is working correctly
	fmt.Println("Value going in:", macbook)
	
	// Store the Go object using NSUserDefaults
	ud.SetObjectForKey(macbook, "My Laptop")
	
	// Get the Go object
	var aComputer Computer
	rawBytes := ud.ObjectForKey("My Laptop")
	json.Unmarshal(rawBytes, &aComputer)
	fmt.Println("Value coming out:", aComputer)
	success := aComputer.Model == "MacBook Air" && aComputer.RamSize == 16 &&
	aComputer.CPU == "M1" && aComputer.Manufacturer == "Apple"
	if success == true {
		fmt.Println("Test 2 - Pass")
	} else {
		fmt.Println("Test 2 - Fail")
	}

	// stringForKey test
	value := "One two three"
	key := "numbers"
	ud.SetObjectForKey(value, key)
	strValue := ud.StringForKey(key)
	fmt.Println("Expected:", value, "Received Value:", strValue)
	if strValue == value {
		fmt.Println("Test 3 - Pass")
	} else {
		fmt.Println("Test 3 - Fail")
	}
}

@tmc tmc deleted the add-nsuserdefaults branch July 4, 2023 10:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Request: add NSUserDefaults class
3 participants