как вызвать код objective-c из swift

<h1>на новом языке swift от apple, как можно назвать код objective-c?</h1><p>apple упомянула, что они могут сосуществовать в одном приложении, но означает ли это, что можно технически повторно использовать старые классы, созданные в objective-c, при создании новых классов в swift?</p><h1>рассуждение</h1><p>objective-c является независимым от платформы языком, тогда как swift зависит от платформы. поэтому написание не зависящего от платформы кода (библиотек бизнес-логики) в swift было бы неразумно. тем не менее, написание платформо-зависимого кода в нем (например, связанный с интерфейсом) вполне подойдет. не сказать, что это была бы хорошая идея, однако это определенно интерес.</p>

<h1>использование классов objective c в swift</h1><p>** если у вас есть существующий класс, который вы хотели бы использовать, выполните <b>шаг 2</b> а затем перейти к <b>шаг 5</b>, (в некоторых случаях мне пришлось добавить явный <code>#import <foundation/foundation.h</code> к более старому файлу objective-c.) **</p><h3>шаг 1: добавить реализацию objective-c - .m</h3><p>добавьте файл <code>.m</code> в свой класс и назовите его <code>customobject.m</code>.</p><h3>шаг 2: добавьте заголовок моста</h3><p>при добавлении файла <code>.m</code> вы, скорее всего, получите приглашение, которое выглядит следующим образом:</p><p><img src="https://i.stack.imgur.com/naklz.png" alt="enter image description here"></p><p>нажмите <b>да</b> !</p><p>если вы не видели подсказку или случайно удалили соединительный заголовок, добавьте новый файл <code>.h</code> в свой проект и назовите его <code><#yourprojectname#>-bridging-header.h</code>.</p><p>в некоторых ситуациях, особенно при работе со средами objective c, вы не добавляете класс objective c явно, и xcode не может найти компоновщик. в этом случае создайте файл <code>.h</code> с именем, указанным выше, а затем убедитесь, что вы связали его путь в настройках проекта вашей цели следующим образом:</p><p><img src="https://i.stack.imgur.com/8liwf.gif" alt="enter image description here"></p><p><b>заметка</b></p><p>рекомендуется связывать ваш проект с помощью макроса <code>$(srcroot), чтобы, если вы перемещаете свой проект или работаете над ним с другими, используя удаленный репозиторий, он все равно будет работать. $(srcroot)</code> можно рассматривать как каталог, содержащий ваш файл .xcodeproj. это может выглядеть так:</p><pre><code>$(srcroot)/folder/folder/<#yourprojectname#>-bridging-header.h </code></pre><h3>шаг 3: добавьте заголовок objective c - .h</h3><p>добавьте другой файл <code>.h</code> и назовите его <code>customobject.h</code>.</p><h3>шаг 4: создайте свой класс objective-c</h3><p>в <code>customobject.h</code></p><pre><code>#import <foundation/foundation.h> @interface customobject : nsobject @property (strong, nonatomic) id someproperty; - (void) somemethod; @end </code></pre><p>в <code>customobject.m</code></p><pre><code>#import "customobject.h" @implementation customobject - (void) somemethod { nslog(@"somemethod ran"); } @end </code></pre><h3>шаг 5: добавьте класс в bridging-header</h3><p>в <code>yourproject-bridging-header.h</code>:</p><pre><code>#import "customobject.h" </code></pre><h3>шаг 6: используйте свой объект</h3><p>в <code>someswiftfile.swift</code>:</p><pre><code>var instanceofcustomobject: customobject = customobject() instanceofcustomobject.someproperty = "hello world" println(instanceofcustomobject.someproperty) instanceofcustomobject.somemethod() </code></pre><p>нет необходимости явно импортировать; это то, для чего предназначен соединительный заголовок.</p><h1>использование swift классов в objective-c</h1><h3>шаг 1. создание нового класса swift</h3><p>добавьте файл <code>.swift</code> в свой проект и назовите его <code>myswiftobject.swift</code>.</p><p>в <code>myswiftobject.swift</code>:</p><pre><code>import foundation class myswiftobject : nsobject { var someproperty: anyobject = "some initializer val" init() {} func somefunction(somearg:anyobject) -> string { var returnval = "you sent me \(somearg)" return returnval } } </code></pre><h3>шаг 2. импорт файлов swift в класс objc</h3><p>в <code>somerandomclass.m</code>:</p><pre><code>#import "<#yourprojectname#>-swift.h" </code></pre><p>файл: <code><#yourprojectname#>-swift.h</code> уже должен быть создан автоматически в вашем проекте, даже если вы его не видите.</p><h3>шаг 3: используйте свой класс</h3><pre><code>myswiftobject * myob = [myswiftobject new]; nslog(@"myob.someproperty: %@", myob.someproperty); myob.someproperty = @"hello world"; nslog(@"myob.someproperty: %@", myob.someproperty); // original nsstring * retstring = [myob somefunction:@"arg"]; // xcode10 expands the external arg here nsstring * retstring = [myob somefunctionwithsomearg:@"arg"];| nslog(@"retstring: %@", retstring); </code></pre><h2>замечания:</h2><p><b>1.</b> codecompletion вел себя не так точно, как хотелось бы. в моей системе выполнение быстрой сборки с помощью "cmd + r", казалось, помогло swift найти некоторый код objective-c и наоборот.</p><p><b>2.</b> если вы добавляете файл <code>.swift</code> в более старый проект и получаете сообщение об ошибке: <code>dyld: library not loaded: @rpath/libswift\_stdlib\_core.dylib</code>, попробуйте полностью <a href="https://stackoverflow.com/q/24002836/2611971">перезапуск xcode</a> .</p><p><b>3.</b> хотя изначально было возможно использовать чистые классы swift в objective-c с помощью префикса <code>@objc</code>, после swift 2.0 это больше невозможно. смотрите историю изменений для оригинального объяснения. если эта функция будет включена в будущих версиях swift, ответ будет обновлен соответствующим образом.</p>

<p>см. руководство apple по <a href="https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/buildingcocoaapps/index.html#//apple\_ref/doc/uid/tp40014216">использование swift с какао и objective-c</a> . в этом руководстве рассказывается, как использовать код objective c и c из swift и наоборот, и даются рекомендации по преобразованию проекта или микшированию и сопоставлению частей objective c/c и swift. в существующем проекте.</p><p>компилятор автоматически генерирует синтаксис swift для вызова функций c и методов objective-c. как видно из документации, эта цель-c:</p><pre><code>uitableview *mytableview = [[uitableview alloc] initwithframe:cgrectzero style:uitableviewstylegrouped]; </code></pre><p>превращается в этот swift код:</p><pre><code>let mytableview: uitableview = uitableview(frame: cgrectzero, style: .grouped) </code></pre><p>xcode также выполняет этот перевод на лету - вы можете использовать open quickly при редактировании файла swift и ввести имя класса objective-c, и он перенесет вас в версию заголовка класса с поддержкой swift. , (вы также можете получить это, нажав cmd на символ api в файле swift.) и всю справочную документацию по api в <a href="https://developer.apple.com/library/prerelease/ios/">ios 8</a> и <a href="https://developer.apple.com/library/prerelease/osx/">os x v10.10 (yosemite)</a> библиотеки разработчика видны как в objective-c, так и в swift (например, <a href="https://developer.apple.com/library/prerelease/ios/documentation/uikit/reference/uiview\_class/index.html"><code>uiview</code></a> ).</p>

<p>ниже приведены пошаговые инструкции по использованию кода objective c (в данном случае, среды, предоставляемой сторонней организацией) в проекте swift:</p><ol> <li><strong> добавьте любой файл objective-c в проект swift </strong>, выбрав файл -> новый -> новый файл -> файл objective-c , после сохранения <strong> xcode спросит, хотите ли вы добавить соединительный заголовок </strong>. выберите "<strong> да </strong>". <a href="http://www.derrrick.com/stackoverflow/1-empty-file.gif">gif: добавление пустого файла в проект и создание заголовка моста http://www.derrrick.com/stackoverflow/1-empty-file.gif</a> </li> </ol><p>в простых шагах:</p><ol> <li> <p>появится приглашение, а затем нажмите "ок". если оно не появится, мы создадим его вручную, как показано ниже ... создайте один файл заголовка из источника ios и присвойте ему имя projectname-bridging-header (пример: test -bridging-header), а затем перейдите к настройке сборки в коде компилятора swift -> мост objective-c, добавьте имя моста objective-c .. (test/test-bridging-header.h). да, это завершено.</p> </li> <li> <p>при желании удалите добавленный вами файл objective-c (с именем "что-нибудь" на изображении gif выше). вам это больше не нужно.</p> </li> <li> <p><strong> откройте файл заголовка моста </strong> - имя файла имеет вид <strong> [yourproject] -bridging-header.h </strong>. это включает предоставленный xcode комментарий. <strong> добавьте строку кода для файла objective-c, который вы хотите включить </strong>, например сторонний фреймворк. например, чтобы добавить mixpanel в ваш проект, вам нужно добавить следующую строку кода в заголовочный файл моста:</p> <pre>#import "mixpanel.h"</pre></li> <li> <p>теперь в любом файле swift вы можете <strong> использовать существующий код objective-c в синтаксисе swift </strong> (в случай этого примера, и вы можете вызвать методы mixpanel sdk и т. д.). вам необходимо ознакомиться с тем, как xcode переводит objective-c в swift. <a href="https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps">руководство apple</a> это краткое чтение. или посмотрите этот ответ для неполного резюме.</p> </li> </ol><p>пример для mixpanel:</p><pre><code>func application(application: uiapplication, didfinishlaunchingwithoptions launchoptions: [nsobject: anyobject]?) -> bool { mixpanel.sharedinstancewithtoken("your-token") return true } </code></pre><p>это оно!</p><p>примечание: <strong> если вы удалите файл заголовка моста из своего проекта </strong>, обязательно зайдите в настройки сборки и удалите значение для "<strong> заголовок моста objective-c </strong> "в разделе" компилятор swift - генерация кода ".</p>

<p>вы можете прочитать хороший пост <em> <a href="https://medium.com/@stigi/swift-cocoapods-da09d8ba6dd2">swift & cocoapods</a> </em>. по сути, нам нужно создать файл заголовка моста и поместить туда все заголовки objective-c. и тогда нам нужно сослаться на это из наших настроек сборки. после этого мы можем использовать код objective-c.</p><pre><code>let manager = afhttprequestoperationmanager() manager.get( "http://example.com/resources.json", parameters: nil, success: { (operation: afhttprequestoperation!, responseobject: anyobject!) in println("json: " + responseobject.description) }, failure: { (operation: afhttprequestoperation!, error: nserror!) in println("error: " + error.localizeddescription) }) </code></pre><p>также взгляните на документ apple <em> <a href="https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/buildingcocoaapps/mixandmatch.html">также используя swift с cocoa и objective-c</a> </em>.</p>

<p>я написал простой проект xcode 6, в котором показано, как смешивать код c++, objective-c и swift:</p><p> <a href="https://github.com/romitagl/shared/tree/master/c-objc-swift/performance\_console">https://github.com/romitagl/shared/tree/master/c-objc-swift/performance\_console</a> </p><p>в частности, пример <strong> <em> вызывает функцию objective-c и c++ из swift </em> </strong>.</p><p>ключ должен создать общий заголовок project-bridging-header.h и поместить туда заголовки objective-c.</p><p>пожалуйста, скачайте проект как полный пример.</p>

<p>цитата из <a href="https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/buildingcocoaapps/index.html#//apple\_ref/doc/uid/tp40014216">документация</a> :</p><blockquote> <p>любую среду objective-c (или библиотеку c), которая доступна в виде модуля, можно импортировать непосредственно в swift. это включает в себя все системные инфраструктуры objective-c, такие как foundation, uikit и spritekit, а также общие библиотеки c, поставляемые с системой. например, чтобы импортировать foundation, просто добавьте этот оператор импорта в начало файла swift, в котором вы работаете:</p> <p><code>import foundation</code></p> <p>этот импорт делает все api-интерфейсы foundation, включая nsdate, nsurl, nsmutabledata и все их методы, свойства и категории, непосредственно доступными в swift.</p> </blockquote>

<h3>еще одна вещь, которую я хотел бы добавить здесь:</h3><p>я очень благодарен за ответ @ logan. это очень помогает для создания файла моста и настроек.</p><p>но после выполнения всех этих шагов я все еще не получаю класс objective-c в swift.</p><p>я использовал библиотеку <code>cocoapods</code> и интегрировал ее в свой проект. который является <code>pod "pop"</code>.</p><p>так что, если вы используете модули objective c в swift, то есть вероятность, что вы не сможете получить или <code>import</code> классы в swift.</p><p>простая вещь, которую вы должны сделать, это:</p><ol> <li>перейдите в файл <code><your-project>-bridging-header</code> и</li> <li>заменить оператор <code>#import <objc\_framework></code> на <code>@import objc\_framework</code></li> </ol><p><strong>например: (поп-библиотека)</strong></p><p>замещать</p><pre><code>#import <pop/pop.h> </code></pre><p>с</p><pre><code>@import pop; </code></pre><p><em> используйте <code>clang import</code>, когда <code>#import</code> не работает. </em></p>

<p>просто примечание для тех, кто пытается добавить библиотеку objective-c в swift: вы должны добавить <strong>- - objc</strong> в <em> настройки сборки </em> -> <em> связывание </em> -> <em> другие флаги компоновщика </em>.</p>

<p>после того, как вы создали заголовок bridging, перейдите в build setting => search для "objective-c bridging header".</p><p>чуть ниже вы найдете файл "" имя заголовка сгенерированного интерфейса objective-c ".</p><p>импортируйте этот файл в свой контроллер представления.</p><p>пример: в моем случае: "dauble-swift.h"</p><p> <a href="https://i.stack.imgur.com/ceuwx.png"><img src="https://i.stack.imgur.com/ceuwx.png" alt="eeter image description here"></a> </p>

<p>нажмите на <em>новое</em> меню файла и выберите файл, выберите язык objective. в то же время он автоматически генерирует файл "objective-c bridging header", который используется для определения некоторого имени класса.</p><p>"заголовок моста objective-c" в разделе "компилятор swift - генерация кода".</p>

<ol> <li>создайте .h файл из newfile -> source -> header file</li> <li>затем сохраните имя файла <em>your\_target\_name-bridging-header.h</em> здесь люди получают общую ошибку, беря имя своего проекта, но это должно быть имя цели проекта, если в случае, когда оба они различны, обычно они одинаковы.</li> <li>затем в настройках сборки найдите <em>objective-c bridging header</em> флаг и введите адрес вновь созданного файла моста, вы можете сделать это, щелкнув правой кнопкой мыши файл -> показать в finder -> перетащить файл в текстовая область, тогда адрес будет заполнен.</li> <li>использование #import <em>your\_objective-c\_file.h</em></li> <li>в файле swift вы можете получить доступ к файлу objc, но только на языке swift.</li> </ol>

<p> <a href="https://i.stack.imgur.com/tabpj.png"><img src="https://i.stack.imgur.com/tabpj.png" alt="enter image description here"></a> я добавил проект на github, включающий небольшой пример для вызова кода objective c из swift.</p><p> <a href="https://github.com/crazypro007/bridgingtestproject">вызовите класс objectivec из swift</a> </p>

<p><strong> в проекте swift 4.2.1 в xcode 10.1 вы можете легко добавить файл objective-c. выполните следующие действия, чтобы связать файл objective-c с проектом swift. </strong></p><p>step\_01: создайте новый проект xcode, используя язык swift:</p><p><code>file</code>> <code>new</code>> <code>project</code>> <code>objc</code>.</p><p>шаг\_02: в проект swift добавьте новый файл objective-c:</p><p><code>file</code>> <code>new</code>> <code>file...</code>> <code>macos</code>> <code>objective-c file</code>.</p><p>шаг\_03: если вы добавляете новый файл objective-c в проект swift в самый первый раз, xcode спросит вас:</p><p><code>would you like to configure an objective-c bridging header</code>?</p><p> <a href="https://i.stack.imgur.com/0bdmt.png"><img src="https://i.stack.imgur.com/0bdmt.png" alt="enter image description here"></a> </p><p>step\_04: выберите опцию:</p><p><code>create bridging header</code>.</p><p>шаг\_05: будет создан соответствующий файл с именем:</p><p><code>objc-bridging-header.h</code>.</p><p> <a href="https://i.stack.imgur.com/xmsgl.png"><img src="https://i.stack.imgur.com/xmsgl.png" alt="enter image description here"></a> </p><p>шаг\_06: теперь вам нужно настроить путь к файлу моста в заголовке моста. в project navigator щелкните проект с именем <code>objc</code> и затем выберите:</p><p><code>build settings</code>> <code>objective-c bridging header</code>> <code>objc-bridging-header.h</code>.</p><p>шаг\_07. перетащите свой <code>objc-bridging-header.h</code> в это поле, чтобы сгенерировать путь к файлу.</p><p> <a href="https://i.stack.imgur.com/p0mev.png"><img src="https://i.stack.imgur.com/p0mev.png" alt="enter image description here"></a> </p><p>шаг\_08. откройте файл <code>objc-bridging-header.h</code> и импортируйте файл objective-c, который вы хотите использовать в файле swift.</p><pre><code>#import "specialobjcfile.m" </code></pre><p>вот содержимое <code>specialobjcfile.m</code>:</p><pre><code>#import <foundation/foundation.h> @interface person: nsobject { @public bool busy; } @property bool busy; @end </code></pre><p>step\_09: теперь в вашем файле swift вы можете использовать класс objective-c:</p><pre><code>override func viewdidload() { super.viewdidload() let myobjccontent = person() print(myobjccontent.busy) } </code></pre><p> <a href="https://i.stack.imgur.com/fht0m.png"><img src="https://i.stack.imgur.com/fht0m.png" alt="enter image description here"></a> <a href="https://i.stack.imgur.com/jiz7a.png"><img src="https://i.stack.imgur.com/jiz7a.png" alt="enter image description here"></a> </p>

<p><strong>двусторонний подход для использования target-c target-c</strong></p><p><strong>1</strong></p><ol> <li>создайте файл bridge-header.h в проекте xcode</li> <li>импортировать файл .h в файл заголовка моста</li> <li>установить путь моста-заголовка в настройках сборки.</li> <li>очистить проект</li> </ol><p><strong>2</strong></p><ol> <li>создайте файлы target-c в проекте (он автоматически устанавливает путь в настройках сборки для вас)</li> <li>импортировать файл .h в файл заголовка моста</li> </ol><p><strong>теперь можно идти</strong> <strong>спасибо</strong></p>

<p>apple предоставила официальное руководство в этом документе: <a href="https://developer.apple.com/documentation/swift/imported\_c\_and\_objective-c\_apis/importing\_objective-c\_into\_swift">как-называть цель-c-code-from-swift</a> </p><p>вот соответствующая часть:</p><p><em> чтобы импортировать набор файлов objective-c в код swift в пределах одной и той же цели приложения, вы полагаетесь на <strong> заголовочный файл objective-c для мостов выставить эти файлы swift </strong>. xcode предлагает создать этот заголовок, когда вы добавляете файл swift в существующее приложение objective c или файл objective c в существующее приложение swift. </em></p><p><em> если вы принимаете, xcode создает файл заголовка моста вместе с файлом, который вы создали, и присваивает ему имя, используя имя модуля вашего продукта, за которым следует "-bridging-header.h". в качестве альтернативы вы можете создать соединительный заголовок самостоятельно, выбрав файл> создать> файл> [операционная система]> источник> файл заголовка </em>.</p><p><em> отредактируйте соединительный заголовок, чтобы ваш код objective-c отображался в вашем коде swift: </em></p><ol> <li><em> в заголовке моста objective c импортируйте каждый заголовок objective c, который вы хотите представить, в swift </em>.</li> <li><em> в настройках сборки в swift compiler - generation code убедитесь, что параметр сборки objective-c bridging header имеет путь к файлу заголовка моста. путь должен быть относительно вашего проекта, аналогично тому, как ваш путь info.plist указан в настройках сборки. в большинстве случаев вам не нужно изменять этот параметр. </em></li> </ol><p>любые общедоступные заголовки objective c, перечисленные в заголовке моста, видны swift.</p>

<p>logans <a href="https://stackoverflow.com/a/24005242/1084174">ответ</a> работает нормально, за исключением последнего <code>swift 5</code>, который выдает ошибку компилятора. вот исправление для тех, кто работает над swift 5.</p><h2>swift 5</h2><pre><code>import foundation class myswiftobject : nsobject { var someproperty: anyobject = "some initializer val" as anyobject override init() {} func somefunction(somearg:anyobject) -> string { let returnval = "you sent me \(somearg)" return returnval } } </code></pre>