<commit_before>#lang scribble/doc
@(require scribble/manual
          scribble/eval
          (for-label racket/base
                     racket/contract
                     ffi/unsafe/objc
                     (except-in ffi/unsafe ->)
                     (only-in ffi/objc objc-unsafe!)
                     (only-in scheme/foreign unsafe!)))

@(define objc-eval (make-base-eval))
@(interaction-eval #:eval objc-eval (define-struct cpointer:id ()))

@(define seeCtype
   @elem{see @secref["ctype"]})

@title{Objective-C FFI}

@defmodule[ffi/unsafe/objc]{The
@racketmodname[ffi/unsafe/objc] library builds on
@racketmodname[ffi/unsafe] to support interaction with
@link["http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/"]{Objective-C}.}

The library supports Objective-C interaction in two layers. The upper
layer provides syntactic forms for sending messages and deriving
subclasses. The lower layer is a thin wrapper on the
@link["http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/ObjCRuntimeRef/index.html"]{Objective-C
runtime library} functions. Even the upper layer is unsafe and
relatively low-level compared to normal Racket libraries, because
argument and result types must be declared in terms of FFI C types
(@seeCtype).

@; ----------------------------------------------------------------------

@section{FFI Types and Constants}

@defthing[_id ctype?]{

The type of an Objective-C object, an opaque pointer.}

@defthing[_Class ctype?]{

The type of an Objective-C class, which is also an @racket[_id].}

@defthing[_Protocol ctype?]{

The type of an Objective-C protocol, which is also an @racket[_id].}

@defthing[_SEL ctype?]{

The type of an Objective-C selector, an opaque pointer.}

@defthing[_BOOL ctype?]{

The Objective-C boolean type. Racket values are converted for C in the
usual way: @racket[#f] is false and any other value is true. C values
are converted to Racket booleans.}

@defthing[YES boolean?]{

Synonym for @racket[#t]}

@defthing[NO boolean?]{

Synonym for @racket[#f]}

@; ----------------------------------------------------------------------

@section{Syntactic Forms and Procedures}

@defform*/subs[[(tell result-type obj-expr method-id)
                (tell result-type obj-expr arg ...)]
               ([result-type code:blank
                             (code:line #:type ctype-expr)]
                [arg (code:line method-id arg-expr)
                     (code:line method-id #:type ctype-expr arg-expr)])]{

Sends a message to the Objective-C object produced by
@racket[obj-expr]. When a type is omitted for either the result or an
argument, the type is assumed to be @racket[_id], otherwise it must
be specified as an FFI C type (@seeCtype).

If a single @racket[method-id] is provided with no arguments, then
@racket[method-id] must not end with @litchar{:}; otherwise, each
@racket[method-id] must end with @litchar{:}.

@examples[
#:eval objc-eval
(eval:alts (tell NSString alloc) (make-cpointer:id))
(eval:alts (tell (tell NSString alloc)
                 initWithUTF8String: #:type _string "Hello")
           (make-cpointer:id))
]}

@defform*[[(tellv obj-expr method-id)
           (tellv obj-expr arg ...)]]{

Like @racket[tell], but with a result type @racket[_void].}

@defform[(import-class class-id ...)]{

Defines each @racket[class-id] to the class (a value with FFI type
@racket[_Class]) that is registered with the string form of
@racket[class-id]. The registered class is obtained via
@racket[objc_lookUpClass].

@examples[
#:eval objc-eval
(eval:alts (import-class NSString) (void))
]

A class accessed by @racket[import-class] is normally declared as a
side effect of loading a foreign library. For example, if you want to
import the class @tt{NSString} on Mac OS X, the @filepath{Foundation}
framework must be loaded, first. Beware that if you use
@racket[import-class] in DrRacket or a module that @racket[require]s
@racketmodname[racket/gui/base], then @filepath{Foundation} will have
been loaded into the Racket process already. To avoid relying on other
libraries to load @filepath{Foundation}, explicitly load it with
@racket[ffi-lib]:

@examples[
#:eval objc-eval
(eval:alts (ffi-lib
            "/System/Library/Frameworks/Foundation.framework/Foundation") (void))
(eval:alts (import-class NSString) (void))
]}
<commit_msg>docs tweak<commit_after>#lang scribble/doc
@(require scribble/manual
          scribble/eval
          (for-label racket/base
                     racket/contract
                     ffi/unsafe/objc
                     (except-in ffi/unsafe ->)
                     (only-in ffi/objc objc-unsafe!)
                     (only-in scheme/foreign unsafe!)))

@(define objc-eval (make-base-eval))
@(interaction-eval #:eval objc-eval (define-struct cpointer:id ()))

@(define seeCtype
   @elem{see @secref["ctype"]})

@title{Objective-C FFI}

@defmodule[ffi/unsafe/objc]{The
@racketmodname[ffi/unsafe/objc] library builds on
@racketmodname[ffi/unsafe] to support interaction with
@link["http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/"]{Objective-C}.}

The library supports Objective-C interaction in two layers. The upper
layer provides syntactic forms for sending messages and deriving
subclasses. The lower layer is a thin wrapper on the
@link["http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/ObjCRuntimeRef/index.html"]{Objective-C
runtime library} functions. Even the upper layer is unsafe and
relatively low-level compared to normal Racket libraries, because
argument and result types must be declared in terms of FFI C types
(@seeCtype).

@; ----------------------------------------------------------------------

@section{FFI Types and Constants}

@defthing[_id ctype?]{

The type of an Objective-C object, an opaque pointer.}

@defthing[_Class ctype?]{

The type of an Objective-C class, which is also an @racket[_id].}

@defthing[_Protocol ctype?]{

The type of an Objective-C protocol, which is also an @racket[_id].}

@defthing[_SEL ctype?]{

The type of an Objective-C selector, an opaque pointer.}

@defthing[_BOOL ctype?]{

The Objective-C boolean type. Racket values are converted for C in the
usual way: @racket[#f] is false and any other value is true. C values
are converted to Racket booleans.}

@defthing[YES boolean?]{

Synonym for @racket[#t]}

@defthing[NO boolean?]{

Synonym for @racket[#f]}

@; ----------------------------------------------------------------------

@section{Syntactic Forms and Procedures}

@defform*/subs[[(tell result-type obj-expr method-id)
                (tell result-type obj-expr arg ...)]
               ([result-type code:blank
                             (code:line #:type ctype-expr)]
                [arg (code:line method-id arg-expr)
                     (code:line method-id #:type ctype-expr arg-expr)])]{

Sends a message to the Objective-C object produced by
@racket[obj-expr]. When a type is omitted for either the result or an
argument, the type is assumed to be @racket[_id], otherwise it must
be specified as an FFI C type (@seeCtype).

If a single @racket[method-id] is provided with no arguments, then
@racket[method-id] must not end with @litchar{:}; otherwise, each
@racket[method-id] must end with @litchar{:}.

@examples[
#:eval objc-eval
(eval:alts (tell NSString alloc) (make-cpointer:id))
(eval:alts (tell (tell NSString alloc)
                 initWithUTF8String: #:type _string "Hello")
           (make-cpointer:id))
]}

@defform*[[(tellv obj-expr method-id)
           (tellv obj-expr arg ...)]]{

Like @racket[tell], but with a result type @racket[_void].}

@defform[(import-class class-id ...)]{

Defines each @racket[class-id] to the class (a value with FFI type
@racket[_Class]) that is registered with the string form of
@racket[class-id]. The registered class is obtained via
@racket[objc_lookUpClass].

@examples[
#:eval objc-eval
(eval:alts (import-class NSString) (void))
]

A class accessed by @racket[import-class] is normally declared as a
side effect of loading a foreign library. For example, if you want to
import the class @tt{NSString} on Mac OS X, the @filepath{Foundation}
framework must be loaded, first. Beware that if you use
@racket[import-class] in DrRacket or a module that @racket[require]s
@racketmodname[racket/gui/base], then @filepath{Foundation} will have
been loaded into the Racket process already. To avoid relying on other
libraries to load @filepath{Foundation}, explicitly load it with
@racket[ffi-lib]:

@interaction[
#:eval objc-eval
(eval:alts (ffi-lib
            "/System/Library/Frameworks/Foundation.framework/Foundation") (void))
(eval:alts (import-class NSString) (void))
]}

{'fraction_non_alphanumeric': 0.14318706697459585, 'fraction_numerical': 0.00023094688221709007, 'mean_word_length': 3.1759884281581483, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6069012', 'n_tokens_mistral': 2737, 'n_tokens_neox': 2602, 'n_words': 889}