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

Fix nil issue with several Array and Dictionary methods #247

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

programmingkidx
Copy link
Contributor

Several foundation methods take a list of objects and expect a nil to be used to terminate the list. Problem is the nil these methods want is an Objective-c nil. Using Go's nil causes a crash to take place.

This pull request fixes the issue with several nil terminated methods. The way I fixed the issue was by introducing a new system that uses a file called special.go to override and prevent the generation of specified methods.

A new folder called special will be in the "generated" folder of DarwinKit. In this folder will be a platform folder. Currently we have a macOS folder. Inside the platform folder is a framework folder. This currently has a foundation folder. Inside this folder is a file called special.go. This file will contain the definition for methods that we don't want the generation system to make. To tell the generation system not to try to generate any method, the special.go file will contain a table. This table has this format:

/*
begin-skip
"class", "selector:", "note"
end-skip
*/

It is all located inside a comment. It begins with the text "begin-skip" on its own line, and ends with the text "end-skip" on its own line. Between these lines will be three fields that are separated by commas and each is wrapped with double quotes. The fields will be an objective-c class name, a selector, and a note.
Example: "NSMutableDictionary", "initWithObjectsAndKeys:", "using custom implementation"

With this pull request methods like MutableDictionary's InitWithObjectsAndKeys() will actually work. Go's nil can be used to terminate the list or it can be omitted.

@progrium
Copy link
Owner

progrium commented Mar 7, 2024

Since only certain files are generated, you could make this "special file" in the target package. As long as it doesn't have ".gen" in the filename. Seems like an easier approach you could have used? Unless I'm missing something for this new approach.

@progrium
Copy link
Owner

Also, couldn't we just convert go nil to objc nil somewhere?

@programmingkidx
Copy link
Contributor Author

Since only certain files are generated, you could make this "special file" in the target package. As long as it doesn't have ".gen" in the filename. Seems like an easier approach you could have used? Unless I'm missing something for this new approach.

That could work.

@programmingkidx
Copy link
Contributor Author

Also, couldn't we just convert go nil to objc nil somewhere?

That would not work. As soon as a call to say NSArray's dictionaryWithObjectsAndKeys: from a Go wrapper a crash would happen.

@progrium
Copy link
Owner

Also, couldn't we just convert go nil to objc nil somewhere?

That would not work. As soon as a call to say NSArray's dictionaryWithObjectsAndKeys: from a Go wrapper a crash would happen.

I guess to clarify are we trying to make passing nil work or are we trying to change these methods to not need nil?

@programmingkidx
Copy link
Contributor Author

I guess to clarify are we trying to make passing nil work or are we trying to change these methods to not need nil?

Actually both. For people who want to stick with the Objective-c convention of terminating an array with nil, they win. For people who want to move away from terminating an array with nil, they win too.

This method is used to handle nil. It might be able to explain things:

// create an array for values and a array for keys using one array
 func createKeyValueArrays(args []objc.IObject) (unsafe.Pointer, unsafe.Pointer) {
 	keys := make([]objc.IObject, 0)
 	values := make([]objc.IObject, 0)
 	for i := 0; i < len(args); i++ {
 		if i%2 == 0 {
 			// if last item is nil
 			if i == len(args)-1 && args[i] == nil {
 				continue // remove terminating nil
 			}
 			values = append(values, args[i])
 		} else {
 			keys = append(keys, args[i])
 		}
 	}
 	valuesArray := objc.ToNSArray(reflect.ValueOf(values))
 	keysArray := objc.ToNSArray(reflect.ValueOf(keys))
 	return keysArray, valuesArray
 }

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.

2 participants