c++swiftobjective-cpointershunspell

Using C++ / Objective-C package (Hunspell) function in Swift with char*** argument


I'm a recent Swift learner and now I'm trying to use following package: https://github.com/aaronSig/Hunspell-iOS

The package itself is written using C++ and has some headers for Objective-C. I've added *-Bridging-Header.h file and have been able to use the package inside Swift code, but now I don't understand how to use it properly:

enter image description here

The comments for Objective-C headers for the library say following:

/* suggest(suggestions, word) - search suggestions
 * input: pointer to an array of strings pointer and the (bad) word
 *   array of strings pointer (here *slst) may not be initialized
 * output: number of suggestions in string array, and suggestions in
 *   a newly allocated array of strings (*slts will be NULL when number
 *   of suggestion equals 0.)
 */
LIBHUNSPELL_DLL_EXPORTED int Hunspell_suggest(Hunhandle *pHunspell, char*** slst, const char * word);

But I don't know how to get correct pointer now. I've tried to utilize answers from here: How to pass an array of Swift strings to a C function taking a char ** parameter

But this is where I got so far


Solution

  • I managed to get it working by using the SpellChecker class directly. My bridging header only imports "SpellChecker.h" currently:

    // ProjectName-Bridging-Header.h:
    #import "SpellChecker.h"
    

    I then created a simple wrapper to make it easier to consume the lib:

    class SpellCheckerWrapper {
        /// The instance of the Objective-C `SpellChecker`
        private let spellChecker: SpellChecker
    
        /// Used to avoid possible exceptions during `getSuggestions`.
        private var isLoaded = false
        
        init() {
            spellChecker = SpellChecker()
            // I set the language directly in the constructor but feel free
            // but feel free to make `updateLanguage` public and use it directly.
            updateLanguage("hy_AM")
            isLoaded = true
        }
        
        public func getSuggestions(for word: String) -> [String] {
            if !isLoaded {
                return []
            }
            
            let suggestions = spellChecker.getSuggestionsForWord(word)
            // Remove the log if you don't need it :)
            NSLog("[SpellCheckerWrapper] suggestions: \(suggestions ?? [])")
            return suggestions as? [String] ?? []
        }
    
        public func isSpeltCorrectly(_ word: String) -> Bool {
            return spellChecker.isSpeltCorrectly(word)
        }
        
        private func updateLanguage(_ language: String) {
            spellChecker.updateLanguage(language)
        }
    }
    

    I also had to update the createCharFromCFStringRef function in SpellChecker.mm because it crashed otherwise. I don't remember the exact issue, but here is the updated code in case it throws exceptions for you too:

    static char *createCharFromCFStringRef(CFStringRef cfstr)
    {
        if (cfstr == NULL) {
            return NULL;
        }
        
        CFIndex length = CFStringGetLength(cfstr);
        CFIndex maxSize = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1;
        char *buffer = (char *)malloc(maxSize);
        if (CFStringGetCString(cfstr, buffer, maxSize, kCFStringEncodingUTF8)) {
            return buffer;
        }
        return NULL;
    }
    

    Hope this helps!

    Edit: my full implementation can be found in https://github.com/f-person/hayatar/blob/ee8daae5e221dcf192ac2b7d572c80947453e1bb/Armenian/AutocompleteProvider.swift