애플 이벤트

**애플 이벤트**(Apple event)는 Mac OS의 메시지 기반 프로세스 간 통신 메커니즘으로, 시스템 7에서 처음 등장한 이래 모든 맥 OS의 역사 버전과 macOS에서 지원되고 있다. 애플 이벤트는 "문서 열기" 또는 "파일 인쇄"와 같은 "고수준" 이벤트를 설명하는 반면, 초기 OS는 "클릭" 및 "키 누르기"와 같은 훨씬 더 기본적인 이벤트를 지원했다. 애플 이벤트는 맥 OS 스크립트 시스템인 오픈 스크립팅 아키텍처의 기반을 형성하며 (주요 언어는 애플스크립트이다). 시작점은 **AEDesc**라고 불리는 동적 타입의 확장 가능한 디스크립터 형식으로, 데이터 타입과 타입에 종속적인 데이터 블록을 지정하는 OSType 코드에 불과하다. 예를 들어, OSType 코드 `inte`는 데이터가 빅 엔디언 형식의 4바이트 부호 있는 정수임을 나타낸다. 다양한 공통 단순 타입에 대한 미리 정의된 타입 코드 외에도 두 가지 미리 정의된 구조화된 디스크립터 타입이 있다: 데이터 타입 `reco`(레코드)를 가진 **AERecord**와 타입 `list`(목록 또는 배열)를 가진 **AEList**이다. 이들의 내부 구조는 재귀적으로 중첩된 AEDesc를 포함하며, AERecord는 각 요소를 고유한 레코드 필드 ID(OSType)와 연결한다. 애플 이벤트 관리자는 이러한 구조를 구성하고, 그 내용을 추출하며, 그들이 보유한 내용의 타입을 쿼리하는 API 호출을 제공한다. 애플 이벤트 관리자는 또한 AEDesc를 한 데이터 타입에서 다른 데이터 타입으로 변환하는 강제 변환도 지원한다. 예를 들어 정수와 실수 타입 간의 표준 강제 변환 외에도, 애플리케이션은 사용자 정의 데이터 타입 간의 변환을 처리하는 자체 강제 변환 핸들러 콜백을 설치할 수 있다. 적절한 **애플 이벤트**는 이벤트 목적에 따라 필드가 달라지는 AERecord이다. 또한 애플 이벤트 관리자가 미리 정의한 세트의 속성(이제 이벤트의 매개변수라고 불리는 레코드 필드와는 별개)을 갖는다. 이는 이벤트가 수행해야 할 작업(이벤트 클래스 및 이벤트 ID를 통해), 이벤트가 전송될 대상 주소(로컬 또는 원격 시스템의 프로세스일 수 있음), 그리고 이를 처리하기 위한 다양한 기타 옵션을 지정한다. 원격 시스템은 처음에는 애플토크를 통해 연결되어야 했지만, 맥 OS 9는 TCP/IP를 통한 연결 옵션을 추가했다. 애플 이벤트를 대상 프로세스로 보낸 후, 보내는 프로세스는 애플 이벤트에 대한 응답을 받도록 선택할 수 있다. 여기에는 원래 이벤트의 처리와 관련하여 대상에서 반환된 다양한 정보, 즉 성공/실패를 나타내는 오류 코드, 원래 이벤트에서 요청된 정보 및 기타 적절한 정보가 포함될 수 있다. 애플 이벤트는 애플이벤트 오브젝트 모델의 기반이며, 이는 다시 OSA 및 애플스크립트의 기반이 된다. 2016년 기준으로 애플 이벤트 관리자 API의 공식 구현은 C 및 C++를 포함한 파생 언어에서 사용할 수 있다. 공식 바인딩은 코코아 API를 통해 오브젝티브-C 및 스위프트에서도 제공된다. 펄, UserTalk, 루비, 파이썬을 포함한 다른 언어에서도 (제한적이지만) 비공식 바인딩이 존재한다.
# 오브젝트 모델
**애플이벤트 오브젝트 모델**(AppleEvent Object Model, **AEOM**)은 애플 이벤트 위에 구축된 프로토콜 세트로, 맥 OS의 역사 및 macOS에서 실행되는 애플리케이션들이 서로의 기능을 제어할 수 있게 했다. AEOM의 일부를 구현한 애플리케이션은 애플스크립트를 통해 제어될 수 있었기 때문에 스크립트 가능하다고 불렸다. 안타깝게도, 스크립트 가능성 지원은 맥 OS의 역사 내내 일관성이 없고 파편화되어 있었다. AEOM은 어떤 애플리케이션이든 내부 객체를 게시할 수 있는 구문 계층을 제공하여, 해당 객체들을 표준화된 방식으로 조작할 수 있게 했다. ToolTalk와 같은 다른 유사한 개념들과 달리, 명사와 동사 사이에는 명확하고 직교적인 구분이 있었다. 따라서 "문서 닫기"와 "창 닫기"에 대한 별도의 명령을 제공하는 대신, "문서" 또는 "창" 객체, 또는 애플리케이션이 게시한 다른 객체에 대한 참조를 받을 수 있는 단일 "닫기" 동사가 있었다. 애플리케이션이 AEOM 지원을 통해 제공하는 객체들은 계층 구조로 배열되었다. 최상위에는 null 객체 디스크립터를 통해 참조되는 애플리케이션 자체가 있었다. 다른 객체들은 (재귀적으로) 부모 객체를 지정하고, 해당 부모의 자식임을 식별하는 다른 정보와 함께 AERecord에 모두 수집되어 참조되었다. 부모는 자식들을 열거하거나 특정 클래스의 자식들을 열거할 수 있는 반복자를 제공하여, 애플리케이션이 요소 집합을 다룰 수 있게 했다. 이 시스템은 일반적으로 XML에서 사용되는 문서 객체 모델과 유사했지만, 접근 패턴에는 약간의 차이가 있었다. 각 객체는 요소와 속성을 가질 수 있었다. 요소는 생성되거나 삭제될 수 있는 다른 객체였고, 속성은 생성되거나 삭제될 수는 없지만 조회하거나 변경할 수 있는 값을 가졌다. 예를 들어, 애플리케이션은 현재 열린 문서의 내용을 보여주는 창을 나타내는 하나 이상의 창 요소를 가질 수 있었다. 이 창들은 제목, 위치 및 크기와 같은 속성을 가질 수 있었다. 애플리케이션은 객체에 대해 사용자 정의 동사를 정의할 수 있었다. AEOM은 또한 (기대했던 대로) 애플리케이션이 일관된 방식으로 구현할 표준 동사(예: 열기, 닫기, 요소 생성, 삭제, 데이터 설정, 데이터 가져오기)를 지정했다. 각 동사는 특정 유형 및 클래스의 애플이벤트로 정의되었으며, 특정 유형의 특정 매개변수가 존재할 것으로 예상되었다. 예를 들어, "데이터 가져오기" 이벤트는 속성 값을 얻기 위한 표준 수단이었다. 본질적으로 하나의 매개변수(쿼리할 속성을 식별하는 객체 디스크립터)를 가졌다. 해당 속성의 값은 회신 이벤트로 반환되었다. "데이터 설정" 이벤트는 두 개의 매개변수(설정할 속성의 객체 디스크립터와 속성의 새 값)를 가졌다. 회신 이벤트는 성공 상태 또는 실패 오류 코드만 반환할 것으로 예상되었다. 전체 애플 이벤트 아키텍처는 4바이트 OSType 코드를 사용하여 모든 것을 식별하며, 영어(또는 다른 언어)의 실제 단어나 구를 피한다. 대신, 내부 애플 이벤트 코드와 외부 자연어 설명 간의 대응 관계는 **aete**(AppleEvent Terminology Extension) 리소스를 통해 지정된다. 여기서 "확장"은 애플스크립트 자체에 내장된 표준 용어를 의미한다. 애플리케이션은 애플스크립트 자체의 원래 다국어 설계에 따라 여러 언어에 대한 여러 'aete' 리소스를 제공할 수 있다. 예를 들어, 가상의 그리기 애플리케이션을 제어하는 다음 애플스크립트 시퀀스를 고려해 보자. tell application "ScriptableDraw" set background color of window "New Drawing" to background color of window "Old Drawing" end tell 이것은 실제로 대상 애플리케이션으로 두 개의 애플이벤트를 전송하는 것을 포함한다 (그리고 해당 회신을 수신한다): 첫째, "Old Drawing"이라는 이름으로 식별되는 창의 배경색 속성을 검색하기 위해 get-data 이벤트가 전송된다; 그런 다음 반환된 값을 "New Drawing"이라는 이름의 창의 배경색 속성으로 적용하기 위해 set-data 이벤트가 전송된다. 이러한 종류의 접근 패턴이 일반적이었기 때문에, 애플스크립트는 비주얼 베이직 또는 파스칼에서 발견되는 `with` 문과 유사한 방식으로 명명된 객체로 컨텍스트를 전환하는 `tell` 문을 널리 사용했다. `tell` 다음부터 해당 `end tell`까지의 모든 명령은 기본 객체인 현재 애플리케이션 대신 `tell`에 명명된 객체로 전송되었다. 객체 디스크립터를 통해 다양한 방식으로 객체를 식별할 수 있었다. 가장 흥미로운 방법은 where-절(애플스크립트 용어로는 필터 표현식으로 번역됨)을 사용하는 것이었다. 예를 들어, 애플스크립트 1.0 SDK는 Scriptable Text Editor라는 예제 애플리케이션의 소스 코드를 제공했는데, 이 애플리케이션은 다음과 같은 스크립트에 응답했다. tell application "Scriptable Text Editor" tell window "Example Document" set text style of every word whose length > 7 to bold end tell end tell 오늘날에도 SQL 외의 범용 스크립트 언어에서 이러한 종류의 강력한 기능을 찾기는 드물다. 맥 OS의 역사에서 AEOM을 지원하는 것은 어려운 과정이었다. 애플리케이션 개발자는 객체를 식별하고 수동으로 코드를 작성하여 객체를 주소 지정할 수 있도록 해야 했다. 이는 일반적으로 특정 유형의 "다음" 객체를 반환하는 코드 형태로 이루어져 애플스크립트가 객체들을 반복할 수 있도록 했다. 그러나 OS 자체에 객체 모델이 없었기 때문에 이 작업은 전적으로 개발자의 몫이었고, 많은 개발자가 이를 구현하지 않았다. 이상하게도, 애플 자체의 애플리케이션 프레임워크인 MacApp조차도 GUI 객체를 제외하고는 이러한 모델을 제공하지 않아, 개발자가 데이터 자체를 나타내는 객체를 스크립팅하는 대부분의 작업을 다시 해야 했다. 주로 이러한 이유로 애플스크립트 지원은 그리 널리 퍼지지 않았다. 애플은 다양한 객체 "스위트"를 도입하여 이 문제를 해결하려고 시도했는데, 이는 다양한 유형의 애플리케이션에서 지원될 것으로 예상되는 표준 객체와 동사를 나타냈다. 예를 들어, 모든 애플리케이션은 "코어 스위트"를 지원해야 했고, 텍스트를 편집하는 애플리케이션은 "텍스트 스위트"를 지원해야 했다. 적절한 스위트 집합을 선택함으로써 개발자는 적어도 객체를 노출하는 방법에 대한 계획 작업을 줄일 수 있었다. 그러나 이러한 객체는 일반적으로 시스템 자체의 일부가 아니었기 때문에 (심하게 제한된 TextEdit 편집기를 제외하고), 실제 구현은 개발자에게 맡겨졌다. 이전에는 오픈스텝으로 알려진 시스템인 코코아에서 개발된 애플리케이션은 다른 모든 애플리케이션에서 쿼리할 수 있는 풍부한 객체 런타임을 제공한다. 이는 AEOM 구현을 상당히 쉽게 만들어 평균 애플리케이션에서 필요한 코드 양을 극적으로 줄여준다. 또한 대부분의 코코아 애플리케이션은 주로 코코아 표준 객체로 구성되며, 이 모든 객체는 상당히 광범위한 스크립트 가능성을 제공하도록 업그레이드되었다. 이는 MacApp에서와 같이 GUI 객체뿐만 아니라 텍스트, 테이블 및 다양한 목록 객체를 포함한 내부 데이터 객체에도 적용된다. 텍스트 파일은 내부 "객체 유사" 이름을 사람이 읽을 수 있는 버전으로 매핑하는 데 사용되며, 대부분의 경우 이 파일을 생성하는 것만으로도 대부분의 프로그램에 상당히 많은 스크립트 가능성을 추가할 수 있다. 코코아 애플리케이션은 AEOM 기반이 아니며, 애플이 원래 정의한 표준 객체와 미묘하게 다른 객체를 사용하는 경우가 많지만, 코코아 앱은 일반적으로 "클래식" 앱보다 훨씬 더 스크립트 가능성이 높다. 사실, 어느 정도 스크립트 불가능한 코코아 애플리케이션을 찾는 것은 드문 일이다.
# 스크립팅 브리지
스크립팅 브리지는 애플스크립트와 같은 중간 스크립팅 언어를 사용하지 않고도 애플리케이션들이 서로 통신할 수 있게 해주는 macOS 프레임워크이다. 스크립팅 브리지는 애플스크립트와 마찬가지로 애플리케이션 간 통신을 위해 애플 이벤트를 사용한다.website=Apple Developer documentation 스크립팅 브리지는 일반적으로 오브젝티브-C에서 사용되지만, MacRubylanguage=en-us 및 PyObjC와 같은 오브젝티브-C 브리지를 통해 다른 프로그래밍 언어에서도 사용할 수 있다.
# 더 읽어보기
* . 특히 2.3절 “애플 이벤트”(9–13페이지)를 참조하지만, 애플 이벤트의 역사와 중요성은 이 논문의 다른 곳에서도 논의된다.