Конвертировать Int8? UnsafePointer <Int8>? - PullRequest
0 голосов
/ 11 апреля 2019

Я очень новичок в Swift.Попытка написать приложение Swift, которое вызывает внешний метод Си.Однако компилятор Xcode выдает ошибку о преобразовании типов.Прототип метода C имеет вид:

void * cMethod(const char* string1Path, const char* string2Path, const char* string3Path, const char* string4Path);

Суть кода Swift:

import OpenGLES
import CoreGraphics
import GLKit

var mGLUTWindow: Void?

class myClass {

    mGLUTWindow = nil
    let appBundle = Bundle.main

    let string1 = appBundle.path(forResource: "Init", ofType: "dat")
    let string1Path = Int8((string1?.description)!)

    let string2 = appBundle.path(forResource: "autostart", ofType: "type")
    let string2Path = Int8((string2?.description)!)

    let string3: String? = appBundle.path(forResource: "data", ofType: "") ?? "" + ("/")
    let string3Path = Int8((string3?.description)!)

    mGLUTWindow = cMethod(UnsafePointer(string3Path), string1Path, string2Path, "ios")
}

Компилятор выдает ошибку:

Cannot convert value of type 'Int8?' to expected argument type 'UnsafePointer<Int8>?'

Метод C вводится с помощью соединительного заголовка.Есть ли способ преобразовать это в ожидаемый аргумент?

ПРИМЕЧАНИЕ. Код Swift, приведенный здесь, был взят из файла Objective-C несколько лет назад и сейчас адаптируется для Swift.Я использовал этот конвертер Obj-C в Swift, так как я почти не понимаю Swift и не могу читать Obj-C.Подкладка Obj-C, которую я вставил, имела вид:

NSString * string1 = [[appBundle pathForResource:@"data" ofType:@""] stringByAppendingString:@"/"]; 
const char * string1Path = [string1 cStringUsingEncoding:[NSString defaultCStringEncoding]];

Ответы [ 2 ]

1 голос
/ 11 апреля 2019

Если бы мне дали функцию C и какой-то код, показанный в виде строк Objective-C, я написал бы что-то вроде этого:


var mGLUTWindow: UnsafeRawPointer?

class MyClass {

    func aMethod() {
        let appBundle = Bundle.main

        let string1 = appBundle.path(forResource: "Init", ofType: "dat")!

        let string2 = appBundle.path(forResource: "autostart", ofType: "type")!

        let string3 = (appBundle.path(forResource: "data", ofType: "") ?? "") + ("/")

        mGLUTWindow = UnsafeRawPointer(cMethod(string3, string1, string2, "ios"))
    }
}

В Swift, когда вы передаете String аргументу типа char *, Swift генерирует временный буфер C-строки и передает адрес буфера, вам не нужно вызывать что-то вроде const char * string1Path = [string1 cStringUsingEncoding:[NSString defaultCStringEncoding]];.

Если cMethod сохраняет какой-либо из указателей для последующего использования, вам может понадобиться немного более сложный код, но не ясно, что если нам понадобится такой сложный код, как для текущего описания.

1 голос
/ 11 апреля 2019

Хотя преобразование Int8? в указатель достаточно просто (просто разверните его и используйте оператор & при передаче его в качестве аргумента), ваша реальная проблема заключается в том, что преобразование вашей строки в Int8 в первомместо это ошибка.Значение, которое возвращает Bundle.path(forResource:ofType:), будет представлять собой путь, который выглядит примерно так:

"/Applications/MyApp.app/Contents/Resources/Init.dat"

Тем временем вы пытаетесь преобразовать это значение в Int8, который является целочисленным типом, который можетсохранить значения от -128 до 127, используя инициализатор, который принимает String.Причина, по которой этот инициализатор возвращает необязательное значение, заключается в том, что не каждая строка будет содержать число от -128 до 127, поэтому, если строка является чем-то другим, вы получите nil.

Строка, подобная "37" или "-101" будет преобразован правильно, но строка пути, подобная приведенной выше, всегда просто даст вам nil.

Что вы действительно хотите здесь сделать, это преобразовать String в строку C.Есть несколько различных способов сделать это, но я бы использовал функцию fileSystemRepresentation URL, например:

let url1 = appBundle.url(forResource: "Init", withExtension: "dat")! // instead of path
url1.withUnsafeFileSystemRepresentation { cPath in
    // cPath here is an UnsafePointer<Int8> that you can pass to C APIs inside this block.
}

// Don't let cPath get out here or bad things will happen.

Обратите внимание, что вам нужно сделатьне позволяйте cPath экранировать блок withUnsafeFileSystemRepresentation здесь, поскольку он не определен как допустимый вне этой области.

Также обратите внимание, что из-за ! это приведет к аварийному завершению работы вашего приложения, еслиФайл Init.dat на самом деле не существует внутри вашего приложения, поэтому вам лучше убедиться, что вы включили его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...