UIResponder.h
그럼 고대하던 UIResponder.h 를 읽어보는 시간 :)
#if (defined(USE_UIKIT_PUBLIC_HEADERS) && USE_UIKIT_PUBLIC_HEADERS) || !__has_include(<UIKitCore/UIResponder.h>)
이 코드는 UIKitCore 프레임워크에서 UIResponder.h 헤더 파일을 포함하고 있는지 확인하고, 만약 헤더 파일이 없다면 UIKit public 헤더 파일을 사용할 것인지를 결정하는 조건문입니다.
defined(USE_UIKIT_PUBLIC_HEADERS) && USE_UIKIT_PUBLIC_HEADERS -> 이게 둘 다 있거나?
!__has_include(<UIKitCore/UIResponder.h>) -> UIKitCore 프레임워크에서 UIResponder.h 헤더 파일을 포함하지 않는다면?
(UIResponder.h 헤더 파일이 없을 수가 있나요? chatGPT 선생님께서도 재설치를 권장하셨습니다. '그냥 그런가보다' 하고 지가나야할 것 같습니다.)
*** UIKit public 헤더 파일이란? ***
UIKit public 헤더 파일은 iOS 애플리케이션 개발에 필요한 UIKit 프레임워크의 공개 API를 정의한 헤더 파일입니다. 이 파일은 UIKit 프레임워크에서 제공되는 클래스, 프로퍼티, 메서드 등을 사용하기 위해서는 반드시 포함되어야 하는 파일입니다. UIKit public 헤더 파일은 iOS 애플리케이션 개발에 필수적인 요소로, Objective-C나 Swift 언어로 작성된 코드에서 사용됩니다. 이 파일에는 UIKit에서 제공하는 뷰, 컨트롤러, 레이아웃, 애니메이션, 터치 이벤트 처리 등 다양한 기능들이 포함되어 있습니다.
#import <Foundation/Foundation.h>
#import <UIKit/UIKitDefines.h>
#import <UIKit/UIEvent.h>
#import <UIKit/UIKeyCommand.h>
#import <UIKit/UIPasteConfigurationSupporting.h>
#import <UIKit/UIUserActivity.h>
헤더 파일들을 import 하고
*** 각 헤더의 설명***
Foundation/Foundation.h: Foundation 프레임워크에서 제공하는 클래스와 메서드를 사용하기 위한 헤더 파일입니다.
UIKit/UIKitDefines.h: UIKit 프레임워크에서 정의한 상수와 타입을 사용하기 위한 헤더 파일입니다.
UIKit/UIEvent.h: iOS 애플리케이션에서 발생하는 이벤트를 처리하기 위한 클래스와 프로토콜을 정의한 헤더 파일입니다.
UIKit/UIKeyCommand.h: 키보드 단축키를 처리하기 위한 클래스와 프로토콜을 정의한 헤더 파일입니다.
('Responder 인데 왜 단축키헤더가 들어있지? 했는데!!! 사용자 인터페이스 이벤트 및 키보드 이벤트 처리를 같이하기 때문이었습니다. 지능이슈...)
UIKit/UIPasteConfigurationSupporting.h: 클립보드 기능을 지원하는 클래스와 프로토콜을 정의한 헤더 파일입니다.
UIKit/UIUserActivity.h: 앱 간 데이터 공유를 위한 사용자 활동 정보를 처리하는 클래스와 프로토콜을 정의한 헤더 파일입니다.
(이 파일은 또 왜??? 했는데.. UIKit/UIUserActivity.h 파일이 포함하는 UIUserActivity 클래스가 앱이 실행되지 않은 상태에서 사용자 액션에 응답하고, 해당 앱을 열어 특정 상태로 이동하는 데 사용되기 때문이라고 합니다. )
USE_UIKIT_PUBLIC_HEADERS가 정의되어 있고, 값이 true일 경우 UIKit public 헤더 파일을 사용하며, 값이 false이거나 정의되어 있지 않은 경우에는 UIResponder.h 헤더 파일을 사용합니다. (??? 그러면 UIKit public 헤더 파일이 뭔지부터 공부해야 할 것 같은데요?...)
__has_include 매크로는 현재 컴파일 중인 환경에서 지정된 헤더 파일이 존재하는지 여부를 확인하는데 사용됩니다.
NS_HEADER_AUDIT_BEGIN(nullability, sendability)
NS_HEADER_AUDIT_BEGIN(nullability, sendability)는 Objective-C 코드에서 사용되는 *매크로로서, 코드의 가독성과 안정성을 높이기 위해 사용됩니다.
*NS_HEADER_AUDIT_BEGIN는 애초에 Apple의 Clang 컴파일러에서 매크로이며,nullability 및 sendability 정보를 감사하기(audit) 시작한다는 것을 나타냅니다.
nullability는 변수, 매개변수, 반환 값 등이 null 값을 가질 수 있는지 여부를 나타내는 속성
sendability는 객체가 분산 시스템에서 전송 가능한지 여부를 나타내는 속성
*** Objective-C 코드에서 사용되는 매크로란? ***
Objective-C 코드에서 사용되는 매크로는 C 언어의 매크로 기능을 상속받아 Objective-C 언어에서도 사용할 수 있는 것을 말합니다. 매크로는 코드 내에서 미리 정의된 문자열을 코드의 일부로 대체하여 사용하는 기능을 제공합니다. 대표적으로 #define을 이용해 상수나 함수를 정의하는 경우가 있습니다. Objective-C에서는 C 언어에서 사용하는 매크로 기능을 그대로 사용할 수 있으며, 더불어 Objective-C에서만 사용 가능한 특별한 매크로들도 있습니다. 예를 들어, Objective-C의 클래스 및 프로토콜을 정의할 때 사용하는 @interface와 @protocol 키워드도 사실상 매크로로 동작합니다.
typedef NSDictionary<NSAttributedStringKey, id> * _Nonnull(^UITextAttributesConversionHandler)(NSDictionary<NSAttributedStringKey, id> * _Nonnull);
이 코드는 Objective-C에서 사용되는 *블록 타입인데, UITextAttributesConversionHandler라는 이름으로 선언되어 있습니다. 이 블록 타입은 NSAttributedStringKey와 id를 key-value 쌍으로 가지는 NSDictionary를 입력으로 받고, 같은 타입의 NSDictionary를 반환합니다. 또한 반환되는 NSDictionary와 입력으로 받은 NSDictionary는 둘 다 nonnull입니다.
*** 코드 블록과 블록 타입이란? ***
블록 타입은 코드 블록을 변수로 사용할 수 있는 타입이며, 코드 블록은 실행 가능한 코드의 묶음으로, 변수나 상수, 함수 등과 마찬가지로 하나의 독립된 요소로 취급됩니다. 코드 블록은 ^ 연산자를 사용하여 선언되며, 해당 블록이 수행할 작업과 입력 및 출력 매개변수의 타입을 지정할 수 있습니다.
코드 블록 예제
// 블록 선언
int (^multiply)(int, int) = ^(int a, int b) {
return a * b;
};
// 블록 사용
int result = multiply(5, 10);
NSLog(@"5 * 10 = %d", result); // 5 * 10 = 50 출력
NS_SWIFT_UI_ACTOR
NS_SWIFT_UI_ACTOR는 Swift에서 UI 요소에 대한 비동기 처리를 위해 사용하는 어노테이션입니다. 이 어노테이션은 비동기적으로 실행되는 메서드가 해당 UI 요소에 대한 접근을 제한함으로써 UI 스레드에서의 안정성을 보장합니다.
*** 액터란? ***
액터는 Swift 5.5에서 도입된 새로운 동시성 기능으로, 여러 동시 작업(다중 스레드 환경)에서, 메서드 호출과 상태 접근을 단일 스레드로 제한함으로써, 안전하게 상태를 관리하고 동기화할 수 있습니다.
예제 코드
actor Counter {
private var count = 0
func increment() {
count += 1
}
func getCount() -> Int {
return count
}
}
// Counter 인스턴스 생성
let counter = Counter()
// 동시에 수행되는 작업 1
Task {
await counter.increment()
print("작업 1 결과: \(await counter.getCount())")
}
// 동시에 수행되는 작업 2
Task {
await counter.increment()
print("작업 2 결과: \(await counter.getCount())")
}
실행결과
class와 struct, actor 각각의 예제를 통해 차이를 확인 가능합니다. :)
*** 클래스로 선언 ***
*** struct로 선언 ***
@State 래퍼는 SwiftUI에서 View의 상태를 저장하기 위한 프로퍼티 래퍼입니다. 이 래퍼는 View를 구성하는 값들을 저장하고, 값이 변경되면 View를 업데이트하도록 설계되어 있습니다.
하지만 struct는 값 타입이므로, 값을 복사하여 사용합니다. 따라서 counter.increment() 호출 시, Counter 구조체의 새로운 인스턴스가 생성되고, 그 인스턴스의 count 프로퍼티가 증가합니다. 그리고 작업이 끝나면 해당 인스턴스는 메모리에서 해제됩니다. 따라서 두 작업에서 생성된 Counter 인스턴스는 서로 다른 인스턴스이므로, 값이 공유되지 않습니다. 따라서 count 값이 변하지 않는 것입니다.
@optional
@optional은 Objective-C 프로토콜에서 메소드의 구현이 선택적(Optional)임을 나타내는 예약어입니다. 이 예약어를 사용하면 프로토콜에서 선언한 메소드가 구현되지 않더라도 컴파일 에러가 발생하지 않습니다. 따라서 구현해도 되고 구현하지 않아도 되는 메소드를 정의할 때 사용됩니다. @required는 반대로 해당 메소드가 반드시 구현되어야 함을 나타내는 예약어입니다.
- (void)cut:(nullable id)sender API_AVAILABLE(ios(3.0));
- (void)copy:(nullable id)sender API_AVAILABLE(ios(3.0));
- (void)paste:(nullable id)sender API_AVAILABLE(ios(3.0));
- (void)pasteAndMatchStyle:(nullable id)sender API_AVAILABLE(ios(15.0));
- (void)pasteAndGo:(nullable id)sender API_AVAILABLE(ios(15.0));
- (void)pasteAndSearch:(nullable id)sender API_AVAILABLE(ios(15.0));
- (void)select:(nullable id)sender API_AVAILABLE(ios(3.0));
- (void)selectAll:(nullable id)sender API_AVAILABLE(ios(3.0));
- (void)delete:(nullable id)sender API_AVAILABLE(ios(3.2));
- (void)makeTextWritingDirectionLeftToRight:(nullable id)sender API_AVAILABLE(ios(5.0));
- (void)makeTextWritingDirectionRightToLeft:(nullable id)sender API_AVAILABLE(ios(5.0));
- (void)toggleBoldface:(nullable id)sender API_AVAILABLE(ios(6.0));
- (void)toggleItalics:(nullable id)sender API_AVAILABLE(ios(6.0));
- (void)toggleUnderline:(nullable id)sender API_AVAILABLE(ios(6.0));
- (void)increaseSize:(nullable id)sender API_AVAILABLE(ios(7.0));
- (void)decreaseSize:(nullable id)sender API_AVAILABLE(ios(7.0));
- (void)find:(nullable id)sender API_AVAILABLE(ios(16.0));
- (void)findAndReplace:(nullable id)sender API_AVAILABLE(ios(16.0));
- (void)findNext:(nullable id)sender API_AVAILABLE(ios(16.0));
- (void)findPrevious:(nullable id)sender API_AVAILABLE(ios(16.0));
- (void)useSelectionForFind:(nullable id)sender API_AVAILABLE(ios(16.0));
- (void)updateTextAttributesWithConversionHandler:(NS_NOESCAPE UITextAttributesConversionHandler _Nonnull)conversionHandler API_AVAILABLE(ios(13.0));
- (void)print:(nullable id)sender NS_SWIFT_NAME(printContent(_:)) API_AVAILABLE(ios(15.0));
- (void)rename:(nullable id)sender API_AVAILABLE(ios(16.0));
- (void)duplicate:(nullable id)sender API_AVAILABLE(ios(16.0));
- (void)move:(nullable id)sender API_AVAILABLE(ios(16.0));
- (void)export:(nullable id)sender API_AVAILABLE(ios(16.0));
void는 함수가 반환할 값이 없음을 나타내는 C언어의 예약어입니다. Objective-C에서도 함수의 반환 타입으로 사용됩니다. 따라서 위 코드에서 함수들이 값을 반환하지 않고 어떤 작업을 수행하는 것을 나타냅니다.
코드에 따라 받는 파라미터로 "sender"나 "conversionHandler" 라는 객체를 받을 수 있습니다.
"nullable"은 해당 파라미터가 nil 값을 받을 수 있음을 의미합니다.
API_AVAILABLE 매크로를 사용하여 각 메소드가 iOS 3.0 ~ 16.0 이후부터 사용 가능함을 나타냅니다.
@end
@end는 Objective-C 프로그래밍 언어에서 사용되는 키워드로, 클래스나 프로토콜의 끝을 표시하는 역할을 합니다. @interface나 @implementation과 짝을 이루어 해당 클래스나 프로토콜의 범위를 표시하며, @end를 통해 이 범위가 끝나는 것을 나타냅니다. 이 키워드는 C 프로그래밍 언어의 중괄호({})와 같은 역할을 하며, Objective-C 코드에서는 꼭 필요한 요소 중 하나입니다.
'iOS' 카테고리의 다른 글
API 키 숨기기, xcconfig파일로 (0) | 2023.04.20 |
---|---|
Feature, ViewModel, UseCase (0) | 2023.04.20 |
iOS 터치-3 (0) | 2023.04.16 |
iOS 터치-2 (0) | 2023.04.16 |
iOS 터치-1 (0) | 2023.04.16 |