Swift'ten C nasıl aranır?


136

Swift'ten C rutinlerini çağırmanın bir yolu var mı?

Bir çok iOS / Apple kütüphanesi sadece C'dir ve hala bunları çağırabilirim.

Örneğin, objc çalışma zamanı kitaplıklarını hızlı bir şekilde çağırabilmek istiyorum.

Özellikle, iOS C başlıklarını nasıl köprülersiniz?

Yanıtlar:


106

Evet, elbette Apples C kütüphaneleriyle etkileşime geçebilirsiniz. İşte nasıl açıklanır.
Temel olarak, C tipleri, C işaretçileri vb. Swift nesnelerine çevrilir, örneğin intSwift'teki C bir a CInt.

C ve Swift arasında nasıl köprü kurulacağına dair küçük bir açıklama olarak kullanılabilecek başka bir soru için küçük bir örnek oluşturdum:

main.swift

import Foundation

var output: CInt = 0
getInput(&output)

println(output)

UserInput.c

#include <stdio.h>

void getInput(int *output) {
    scanf("%i", output);
}

cliinput-Köprü-Header.h

void getInput(int *output);

İşte orijinal cevap.


1
IOS / SWIFT'te yeniyim. Hızlı dosyalarda #include <asl.h> günlük c-işlevini kullanmak istiyorum. Kimse?
Dmitry Konovalov

C ++, .cpp dosyalarıyla uyumlu mu ??
Carlos.V

C ++ dosyalarını doğrudan kullanmak için, bir obj-C sarmalayıcısı oluşturmanız gerekir. Uygulamanın (tek başına bir .mm dosyasında bulunması gerekir) Objective-C ++ kodunu (yalnızca bir dosyada Objective-C ve C ++ olan) ve arabirimi (kendi .h biçiminde olması gerekir) içermesini istersiniz. başlık dosyası) saf Objective-C kodu içermelidir, bu yüzden bunları C ++ türlerini uygulamada Objective-C türlerine dönüştürmeniz ve bunları Swift'e göstermeniz gerekir. Daha sonra bu üstbilgiyi objektif-c köprüleme üstbilgisiyle içe aktarabilirsiniz.
William T Froggard

2
“Elbette Apples C kütüphaneleriyle etkileşimde bulunabilirsiniz” Yanlış. Herhangi bir C kütüphanesiyle etkileşim kurabilirsiniz , yalnızca Apple ile sınırlı değildir.
Slipp D.Thompson

Güncelleştirilmiş belge bağlantısı developer.apple.com/documentation/swift/…
MechEthan

9

Derleyici, Objective-C için olduğu gibi C API'sini Swift'e dönüştürür.

import Cocoa

let frame = CGRect(x: 10, y: 10, width: 100, height: 100)

import Darwin

for _ in 1..10 {
    println(rand() % 100)
}

Bkz . Dokümanlardaki Objective-C API'leriyle Etkileşim .


1
Örnek için teşekkürler ve haklısın, bunun nasıl işe yarayacağını görebiliyorum. Ancak bu soruya gerçekten cevap vermiyor, bu da elma C kütüphaneleri olarak adlandırılacaktı. Ama kesinlikle en yakın.
Blaze

Belgenin başka bir yerine bakın. Örneğin, CoreFoundation tarzı "nesneler" ( CFTypeRef) Swift nesnelerine dönüştürülür. Ancak ObjCRuntime.h işlevlerinin çoğu Swift için anlamlı değildir.
rickster

"ObjCRuntime.h işlevlerinin çoğu Swift için anlamlı değil" Neden böyle söylüyorsunuz? Sanırım bir başlık almak ve onu köprülemek için bir yol bulmam gerekiyor. Bu garip görünüyor, ama sanırım bu yol.
Blaze

5

Benim gibi XCode'da yeni olmanız ve Leandro'nun cevabında yayınlanan parçacıkları denemek istiyorsanız :

  1. File-> New-> Proje
  2. Komut Satırı Aracı'nı proje hazır ayarı olarak seçin ve projeye "cliinput" adını verin
  3. proje gezgininde (soldaki mavi panel) sağ tıklayın ve "Yeni Dosya ..." yı seçin
  4. Açılır iletişim kutusunda "UserInput" dosyasına bir ad verin. "Ayrıca bir başlık dosyası oluştur" kutusunun işaretini kaldırın. "İleri" yi tıkladıktan sonra, XCode'un sizin için Bridging-Header.h dosyasını oluşturup oluşturmayacağı sorulacaktır. "Evet" i seçin.
  5. Leandro'nun yukarıdaki cevabından kodu kopyalayıp yapıştırın. Oynat düğmesine tıkladıktan sonra, derlenmeli ve xcode'da alt panelde yerleşik olan terminalde çalışmalıdır. Terminalde bir sayı girerseniz, bir sayı döndürülür.

4

Bu yazı ayrıca clang'ın modül desteğini kullanarak bunun nasıl yapılacağı hakkında iyi bir açıklamaya sahiptir .

Bu, CommonCrypto projesi için nasıl yapılacağı açısından çerçevelenmiştir, ancak genel olarak Swift içinden kullanmak istediğiniz diğer C kitaplıkları için çalışması gerekir.

Kısaca zlib için bunu denedim. Yeni bir iOS çerçeve projesi oluşturdum ve aşağıdaki ile bir module.modulemap dosyası içeren bir zlib dizini oluşturdum:

module zlib [system] [extern_c] {
    header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/include/zlib.h"
    export *
}

Sonra Hedefler -> İkili Kitaplıklarıyla Bağla altında öğe ekle ve libz.tbd ekledim.

Bu noktada inşa etmek isteyebilirsiniz.

Daha sonra aşağıdaki kodu yazabildim:

import zlib

public class Zlib {
    public class func zlibCompileFlags() -> UInt {
        return zlib.zlibCompileFlags()
    }
}

Sen yok olması C işleviyle aynı fonk Swift sınıf adında yukarıdaki vaka I haricinde önünde zlib kitaplık adını koymak ve yeterlilik olmadan Swift fonk uçları uygulama alıkoymalarla kadar tekrar tekrar çağrılan.


3

C ++ durumunda, açılan bu hata vardır:

  "_getInput", referenced from: 

Bir c ++ başlık dosyasına da ihtiyacınız var. Ekle c-bağlantı fonksiyonunuza, ardından köprü başlığında başlık dosyasını içerir:

Hızlı 3

UserInput.h

#ifndef USERINPUT_H
#define USERINPUT_H    

#ifdef __cplusplus
extern "C"{
#endif

getInput(int *output);

#ifdef __cplusplus
}
#endif

UserInput.c

#include <stdio.h>

void getInput(int *output) {
    scanf("%i", output);
}    

main.swift

import Foundation
var output: CInt = 0
getInput(&output)
print(output)

cliinput-Köprü-Header.h

#include "UserInput.h"

İşte bunu açıklayan orijinal video


Bu işe yaramazsa __OBJCBridging-Header'ınıza çek eklemeyi deneyin , örn.#ifdef __OBJC @import UIKit; #endif
Chris Yim

1

İşaretçilerle uğraşırken oldukça farklı bir top balmumu gibi görünüyor. Şimdiye kadar C POSIX readsistem çağrısı çağırmak için ne var :

enum FileReadableStreamError : Error {
case failedOnRead
}

// Some help from: http://stackoverflow.com/questions/38983277/how-to-get-bytes-out-of-an-unsafemutablerawpointer
// and https://gist.github.com/kirsteins/6d6e96380db677169831
override func readBytes(size:UInt32) throws -> [UInt8]? {
    guard let unsafeMutableRawPointer = malloc(Int(size)) else {
        return nil
    }

    let numberBytesRead = read(fd, unsafeMutableRawPointer, Int(size))

    if numberBytesRead < 0 {
        free(unsafeMutableRawPointer)
        throw FileReadableStreamError.failedOnRead
    }

    if numberBytesRead == 0 {
        free(unsafeMutableRawPointer)
        return nil
    }

    let unsafeBufferPointer = UnsafeBufferPointer(start: unsafeMutableRawPointer.assumingMemoryBound(to: UInt8.self), count: numberBytesRead)

    let results = Array<UInt8>(unsafeBufferPointer)
    free(unsafeMutableRawPointer)

    return results
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.