본문 바로가기

프로그래밍/iOS,macOS

swift - objective-c 혼합 사용

브릿징타입

애플에서 제공하는 api와 같이 함수작성 가이드라인을 준수해 작성된 함수들은 Swift, Objective-C 간의 변환이 자동으로 수행된다.  swift의 경우 @objc 어노테이션이 붙은 요소들을 objective-c 헤더에 추가하며, objective-c 는 -Bridgind-Header.h 에 헤더를 import 하면 변환이 일어난다.

 

 

 

Swift 프로젝트에서 Objective-C 사용

 

프로젝트명-Bridging-Header.h 추가

자동으로 지정된 경우에는 설정도 자동으로 이루어지나 수동 추가한 경우

Build Settings의 Objective-C Bridging Header에 해당 파일 지정

$(SRCROOT)/ProjectName/ProjectName-Bridging-Header.h

 

Project > Targets > Build Settings > Defines Module 은 YES

 

브릿지헤더 편집

추가된 Objective-C 헤더 임포트

#import "MyObjectiveClass.h"

 

 

NS_SWIFT_NAME

Objective-C , C 헤더에서 swift에서 호출하는 형태를 변경하는 매크로

+(instancetype)testFunction:(NSUInteger) value NS_SWIFT_NAME(init(value:));

int TestFunction( int a, int b) NS_SWIFT_NAME( testFunction(a:b:));

 

 

Objective-C 프로젝트에서 Swift 사용

 

Project > Targets > Build Settings > Defines Module : YES

Project > Targets > Build Settings > Swift Language Version : 스위프트 버전 

 

헤더파일은 자동으로 생성됨

swift 클래스, 프로토콜은 @objc 식별자 추가

Objective-C 를 상속받은 클래스는 식별자 불필요

 

// swift
@objc protocol MyProtocol {
   @objc func myFunction1()
   @objc optional func myFunction2()
}

// swift
@objc class MyClass {
   @objc func myFunction( val1 : Int, val2: Int ) -> Int { return val1+val2 }
}

// objC
MyClass *test = [[MyClass alloc] init];
[test MyFunction:1 val:1];


// 클래스의 스태틱 메쏘드는 class 키워드 붙임
@objc class MyClass {
   @objc class func MyFunction1() { }
   @objc func MyFunction2() { }
}

 

 


 

 

 

Cocoa NSError

코코아에서는 포인터를 사용해 에러를 받환하는 api들을 swift에서 처리하는 방법

// objC
-(BOOL)removeItemAtURL:(NSURL *)URL error:(NSError **)error;

// swift
func removeItem( at: URL) throws

 

swift 코드를 보면 리턴값 Bool이 사라지고,  NSError** 를 throws 키워드로 대체되었다

objc에서 NS_SWIFT_NOTHROWNSERROR 를 지정하는 경우 throw가 발생하지 않으며, 기존 objc 함수 형태를 그대로 사용해야 한다.

 

 

 

 

 

 

swift에서 objective-c 블록 구문

// objC
typedef void (^BlockFunction)( NSArray *);

// swift
public typealias BlockFunction = ( ([Any]? )->Void


// objC
typedef void(^BlockFunction)(Bool, NSDictionary* );

// swift
public typealias BlockFunction = (Bool, [String, Any])->Void

 

 

 

포인터

//objC
-(void)getValue:(NSString**)value

// swift
func getValue( value: AutoreleasingUnsafeMutablePointer<NSString?>)


// c
void* memcpy( void *dst, const void *src, size_t n);

// swift
memcpy( _ dst: UnsafeMutableRawPointer!, _ src: UnsafeRawPointer, _ n:Int )->UnsafeMutalbRawPointer!



 

UnsafePointer<T>

UnsafeMutablePointer<T> 

UnsafeBufferPointer

UnsafeMutableBufferPointer
UnsafeRawPointer
UnsafeMutableRawPointer

UnsafeRawBufferPointer

UnsafeMutableRawBufferPointer

// 할당
let uint32Pointer = UnsafeMutablePointer<Int32>.allocate( capacity: 1 )
let rawPointer = UnsafeMutableRawPointer.allocate( bytes: 8, alignedTo: 1 )


// 값 설정
uint32Pointer.pointee = 1
uint32Pointer[0] = 1
rawPointer.advanced(by: 0 ).storeBytes( of: Int8(1), as: Int8.self)

// 값 얻기
let value = uint32Pointer.pointee
let value = uint32Pointer[0]

// 원하는 자료형으로 값 얻기
let value = rawPointer.load( as: Int8.self )
let value = rawPointer.advanced( by: 0 ).load( as: Int8.self )


// 해제
defer {
	uint32Pointer.deallocate( capacity: 1 )
    rawPointer.deallocate( bytes: 8, aligned: 1 )
}

// 형변환
// bindMemory() 를 통해 변환하게 되면 이전 포인터로는 접근이 불가
let uint8Pointer = rawPointer.bindMemory( to: UInt8.self, capacity: 1 )
let uint64Pointer = UnsafeRawPointer( uint8Pointer ).bindMemory( to: UInt64.self, capacity: 1)