简体   繁体   中英

How to check whether a particular url path is a directory or not in KMM ios implementation?

I want to covert the corresponding swift method into kotlin for kmm

func checkIfDirectoryExist(fileURL: URL) -> Bool {
     var isDir: ObjCBool = false
     if FileManager.default.fileExists(atPath: fileURL.path, isDirectory: &isDir)
     {
         if isDir.boolValue {
             return true
         } else {
             return false
         }
      }
        return false
}

However I am not sure hot to pass Boolean pointer in kotlin as there are no toCPointer<Boolean>() method neither ** works

Working with Objective-C APIs in Kotlin/Native can be complicated. In many cases such as this one, you're actually interacting with elements of C such as pointers and memory allocation.

Understanding memory use for the isDirectory boolean in Swift

Given the Swift code that you wrote:

var isDir: ObjCBool = false
if FileManager.default.fileExists(atPath: fileURL.path, isDirectory: &isDir) {
   ...

If we consider how this code is running it might help to understand how to write this in Kotlin/Native:

  • The isDir variable is defined as an ObjCBool type.
  • When passing isDir to the fileExists() method, an & is used in order to pass the variable by reference (read/write), not by value (read only).
  • The fileExists() method not only returns the boolean indicator of whether the file exists or not, but it also populates the value of the isDir variable with the result (often in Swift referred to as in/out ).
  • Apple's Objective-C documentation for this method may also be a helpful reference as this shows that the isDirectory argument is a pointer to a boolean ( BOOL * ), as opposed to the return value of the method which is just a boolean ( BOOL ).

Allocating memory for isDir in K/N using memScoped and alloc

In Kotlin/Native, we need to allocate memory for the isDir variable to be populated, which relies on leveraging the kotlinx.cinterop suite of methods.

Using memscoped will allocate memory for use within the block passed as an argument and deallocate that memory when the scope closes. You can see in the declaration of the function that whatever type we return from the block ( R ) will be the same value returned from the call to memScoped ( R ):

inline fun <R> memScoped(block: MemScope.() -> R): R

The MemScoped object allows calling the alloc method to allocate memory for use within this block, and we need to allocate memory for a BooleanVar . Note that alloc returns type T which conforms to CVariable .

memScoped {
    val isDirectory = alloc<BooleanVar>()
    ...
}

Populating the value of isDirectory

When calling the fileExists() method in K/N, if we check the K/N header declaration we can see what it expects to receive for arguments (formatted for readability). Note the isDirectory parameter is a CPointer pointing to a BooleanVar . This is how we knew to allocate memory for a BooleanVar and not some other kind of type:

@kotlinx.cinterop.ObjCMethod 
public open external fun fileExistsAtPath(
    path: kotlin.String, 
    isDirectory: kotlinx.cinterop.CPointer<kotlinx.cinterop.BooleanVar>?
): kotlin.Boolean

Therefore, with the memory that we allocated, which is of type CVariable , we can pass the pointer to that memory (passing by reference) for the fileExistsAtPath method to change the value of it:

val fileExists = NSFileManager.defaultManager.fileExistsAtPath(path, isDirectory.ptr)
                                                                                 ^^^

Lastly, getting the value populated into the BooleanVar CVariable is accessed from the .value property.

Together, the code might look something like:

return memScoped {
    val isDirectory = alloc<BooleanVar>()
    val fileExists = NSFileManager.defaultManager.fileExistsAtPath(path, isDirectory.ptr)
    return@memScoped fileExists && isDirectory.value
}

iOS URL

As for converting the entire method, this is getting a bit into API generalization. You'll need to convert the URL argument to a platform-independent type, such as a simple path (string). This appears to be unrelated to your original question, so although I'll leave this detail out, you might find this blog post helpful .

If you want to go deeper

Kotlin/Native has some documentation on its interoperability with C , however admittedly, I find this documentation a bit difficult to understand with the provided example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM