> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/ios/get-started/samples/interactiveformstest.md).

# InteractiveForms

Sample code in Swift and Obj-C for using Apryse iOS SDK with interactive forms (also known as AcroForms). Capabilities include programatically creating new fields and widget annotations, form filling,

Sample code in Swift and Obj-C for using Apryse iOS SDK with interactive forms (also known as AcroForms). Capabilities include programatically creating new fields and widget annotations, form filling, modifying existing field values, form templating, and flattening form fields.

Learn more about our full [PDF Data Extraction SDK Capabilities](https://apryse.com/capabilities/extraction).

To start your free trial, [get stated with iOS SDK](/ios/get-started/get-started.md).

{% tabs %}
{% tab title="Obj-C" %}
{% code lineNumbers="true" %}

```objc
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2024 by Apryse Software Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

#import <OBJC/PDFNetOBJC.h>
#import <Foundation/Foundation.h>
#import <Foundation/NSDictionary.h>
#import <Foundation/NSArray.h>

//---------------------------------------------------------------------------------------
// This sample illustrates basic PDFNet capabilities related to interactive
// forms (also known as AcroForms).
//---------------------------------------------------------------------------------------

// field_nums has to be greater than 0.
void RenameAllFields(PTPDFDoc* doc, NSString* name, int field_nums)
{
    PTFieldIterator * itr = [doc GetFieldIteratorWithName: name];
    int counter;
    for (counter=1; [itr HasNext]; itr=[doc GetFieldIteratorWithName: name], ++counter)
    {
        PTField *f = [itr Current];
    int update_count = (int)(ceil(counter/(double)field_nums));
        [f Rename: [name stringByAppendingFormat: @"-%d", update_count]];
    }
}

PTObj* CreateCustomButtonAppearance(PTPDFDoc* doc, bool button_down)
{
    // Create a button appearance stream ------------------------------------
    PTElementBuilder *build = [[PTElementBuilder alloc] init];
    PTElementWriter *writer = [[PTElementWriter alloc] init];
    [writer WriterBeginWithSDFDoc: [doc GetSDFDoc] compress: YES];
    
    // Draw background
    PTElement *element = [build CreateRect: 0 y: 0 width: 101 height: 137];
    [element SetPathFill: YES];
    [element SetPathStroke: NO];
    [[element GetGState] SetFillColorSpace: [PTColorSpace CreateDeviceGray]];
    [[element GetGState] SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0.75 y: 0 z: 0 w: 0]];
    [writer WriteElement: element];
    
    // Draw 'Submit' text
    [writer WriteElement: [build CreateTextBegin]];
    {
        NSString *text = @"Submit";
        element = [build CreateTextRunWithFont: text font: [PTFont Create: [doc GetSDFDoc] type: e_pthelvetica_bold embed: NO] font_sz: 12];
        [[element GetGState] SetFillColorWithColorPt: [[PTColorPt alloc] initWithX: 0 y: 0 z: 0 w: 0]];
        
        if (button_down)
            [element SetTextMatrixWithMatrix2D: [[PTMatrix2D alloc] initWithA: 1 b: 0 c: 0 d: 1 h: 33 v: 10]];
        else
            [element SetTextMatrixWithMatrix2D: [[PTMatrix2D alloc] initWithA: 1 b: 0 c: 0 d: 1 h: 30 v: 13]];
        [writer WriteElement: element];
    }
    [writer WriteElement: [build CreateTextEnd]];
    
    PTObj * stm = [writer End];
    
    // Set the bounding box
    [stm PutRect: @"BBox" x1: 0 y1: 0 x2: 101 y2: 37];
    [stm PutName: @"Subtype" name: @"Form"];
    return stm;
}

int main(int argc, char *argv[])
{
    @autoreleasepool {
        int ret = 0;
        [PTPDFNet Initialize: 0];
        
        // The vector used to store the name and count of all fields.
        // This is used later on to clone the fields
        NSMutableDictionary  *field_names = [[NSMutableDictionary alloc] init];
        
        //----------------------------------------------------------------------------------
        // Example 1: Programatically create new Form Fields and Widget Annotations.
        //----------------------------------------------------------------------------------
        @try
        {
            PTPDFDoc *doc = [[PTPDFDoc alloc] init];
            // Create a blank new page and add some form fields.
            PTPage *blank_page = [doc PageCreate: [[PTPDFRect alloc] initWithX1: 0 y1: 0 x2: 612 y2: 792]];
            
            // Text Widget Creation
            // Create an empty text widget with black text.
            PTTextWidget *text1 = [PTTextWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 110 y1: 700 x2: 380 y2: 730] field_name: @""];
            [text1 SetText: @"Basic Text Field"];
            [text1 RefreshAppearance];
            [blank_page AnnotPushBack: text1];
            // Create a vertical text widget with blue text and a yellow background.
            PTTextWidget *text2 = [PTTextWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 50 y1: 400 x2: 90 y2: 730] field_name: @""];
            [text2 SetRotation: 90];
            // Set the text content.
            [text2 SetText: @"    ****Lucky Stars!****"];
            // Set the font type, text color, font size, border color and background color.
            [text2 SetFont: [PTFont Create: [doc GetSDFDoc] type: e_pthelvetica_oblique embed: NO]];
            [text2 SetFontSize: 28];
            [text2 SetTextColor: [[PTColorPt alloc] initWithX: 0 y: 0 z: 1 w: 0] col_comp: 3];
            [text2 SetBorderColor: [[PTColorPt alloc] initWithX: 0 y: 0 z: 0 w: 0] compnum: 3];
            [text2 SetBackgroundColor: [[PTColorPt alloc] initWithX: 1 y: 1 z: 0 w: 0] compnum: 3];
            [text2 RefreshAppearance];
            // Add the annotation to the page.
            [blank_page AnnotPushBack: text2];
            // Create two new text widget with Field names employee.name.first and employee.name.last
            // This logic shows how these widgets can be created using either a field name string or
            // a Field object
            PTTextWidget *text3 = [PTTextWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 110 y1: 660 x2: 380 y2: 690] field_name: @"employee.name.first"];
            [text3 SetText: @"Levi"];
            [text3 SetFont: [PTFont Create: [doc GetSDFDoc] type: e_pttimes_bold embed: NO]];
            [text3 RefreshAppearance];
            [blank_page AnnotPushBack: text3];
            PTField *emp_last_name = [doc FieldCreateWithString: @"employee.name.last" type: e_pttext field_value: @"Ackerman" def_field_value: @""];
            PTTextWidget *text4 = [PTTextWidget CreateWithField: doc pos: [[PTPDFRect alloc] initWithX1: 110 y1: 620 x2: 380 y2: 650] field: emp_last_name];
            [text4 SetFont: [PTFont Create: [doc GetSDFDoc] type: e_pttimes_bold embed: NO]];
            [text4 RefreshAppearance];
            [blank_page AnnotPushBack: text4];
            
            // Signature Widget Creation (unsigned)
            PTSignatureWidget *signature1 = [PTSignatureWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 110 y1: 560 x2: 260 y2: 610] field_name: @""];
            [signature1 RefreshAppearance];
            [blank_page AnnotPushBack: signature1];
            
            // CheckBox Widget Creation
            // Create a check box widget that is not checked.
            PTCheckBoxWidget *check1 = [PTCheckBoxWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 140 y1: 490 x2: 170 y2: 520] field_name: @""];
            [check1 RefreshAppearance];
            [blank_page AnnotPushBack: check1];
            // Create a check box widget that is checked.
            PTCheckBoxWidget *check2 = [PTCheckBoxWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 190 y1: 490 x2: 250 y2: 540] field_name: @"employee.name.check1"];
            [check2 SetBackgroundColor: [[PTColorPt alloc] initWithX: 1 y: 1 z: 1 w: 0] compnum: 3];
            [check2 SetBorderColor: [[PTColorPt alloc] initWithX: 0 y: 0 z: 0 w: 0] compnum: 3];
            // Check the widget (by default it is unchecked).
            [check2 SetChecked: true];
            [check2 RefreshAppearance];
            [blank_page AnnotPushBack: check2];
            
            // PushButton Widget Creation
            PTPushButtonWidget *pushbutton1 = [PTPushButtonWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 380 y1: 490 x2: 520 y2: 540] field_name: @""];
            [pushbutton1 SetTextColor: [[PTColorPt alloc] initWithX: 1 y: 1 z: 1 w: 0] col_comp: 3];
            [pushbutton1 SetFontSize: 36];
            [pushbutton1 SetBackgroundColor: [[PTColorPt alloc] initWithX: 0 y: 0 z: 0 w: 0] compnum: 3];
            // Add a caption for the pushbutton.
            [pushbutton1 SetStaticCaptionText: @"PushButton"];
            [pushbutton1 RefreshAppearance];
            [blank_page AnnotPushBack: pushbutton1];
            
            // ComboBox Widget Creation
            PTComboBoxWidget *combo1 = [PTComboBoxWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 280 y1: 560 x2: 580 y2: 610] field_name: @""];
            // Add options to the combobox widget.
            [combo1 AddOption: @"Combo Box No.1"];
            [combo1 AddOption: @"Combo Box No.2"];
            [combo1 AddOption: @"Combo Box No.3"];
            // Make one of the options in the combo box selected by default.
            [combo1 SetSelectedOption: @"Combo Box No.2"];
            [combo1 SetTextColor: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w: 0] col_comp: 3];
            [combo1 SetFontSize: 28];
            [combo1 RefreshAppearance];
            [blank_page AnnotPushBack: combo1];
            
            // ListBox Widget Creation
            PTListBoxWidget *list1 = [PTListBoxWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 400 y1: 620 x2: 580 y2: 730] field_name: @""];
            // Add one option to the listbox widget.
            [list1 AddOption: @"List Box No.1"];
            // Add multiple options to the listbox widget in a batch.
            NSArray *list_options = [NSArray arrayWithObjects: @"List Box No.2", @"List Box No.3", nil];
            [list1 AddOptions: list_options];
            // Select some of the options in list box as default options
            [list1 SetSelectedOptions: list_options];
            // Enable list box to have multi-select when editing.
            [[list1 GetField] SetFlag: e_ptmultiselect value: true];
            [list1 SetFont: [PTFont Create: [doc GetSDFDoc] type: e_pttimes_italic embed: NO]];
            [list1 SetTextColor: [[PTColorPt alloc] initWithX: 1 y: 0 z: 0 w: 0] col_comp: 3];
            [list1 SetFontSize: 28];
            [list1 SetBackgroundColor: [[PTColorPt alloc] initWithX: 1 y: 1 z: 1 w: 0] compnum: 3];
            [list1 RefreshAppearance];
            [blank_page AnnotPushBack: list1];
            
            // RadioButton Widget Creation
            // Create a radio button group and add three radio buttons in it.
            PTRadioButtonGroup *radio_group = [PTRadioButtonGroup Create: doc field_name: @"RadioGroup"];
            PTRadioButtonWidget *radiobutton1 = [radio_group Add: [[PTPDFRect alloc] initWithX1: 140 y1: 410 x2: 190 y2: 460] onstate: @""];
            [radiobutton1 SetBackgroundColor: [[PTColorPt alloc] initWithX: 1 y: 1 z: 0 w: 0] compnum: 3];
            [radiobutton1 RefreshAppearance];
            PTRadioButtonWidget *radiobutton2 = [radio_group Add: [[PTPDFRect alloc] initWithX1: 310 y1: 410 x2: 360 y2: 460] onstate: @""];
            [radiobutton2 SetBackgroundColor: [[PTColorPt alloc] initWithX: 0 y: 1 z: 0 w: 0] compnum: 3];
            [radiobutton2 RefreshAppearance];
            PTRadioButtonWidget *radiobutton3 = [radio_group Add: [[PTPDFRect alloc] initWithX1: 480 y1: 410 x2: 530 y2: 460] onstate: @""];
            // Enable the third radio button. By default the first one is selected
            [radiobutton3 EnableButton];
            [radiobutton3 SetBackgroundColor: [[PTColorPt alloc] initWithX: 0 y: 1 z: 1 w: 0] compnum: 3];
            [radiobutton3 RefreshAppearance];
            [radio_group AddGroupButtonsToPage: blank_page];
            
            // Custom push button annotation creation
            PTPushButtonWidget *custom_pushbutton1 = [PTPushButtonWidget Create: doc pos: [[PTPDFRect alloc] initWithX1: 260 y1: 320 x2: 360 y2: 360] field_name: @""];
            // Set the annotation appearance.
            [custom_pushbutton1 SetAppearance: CreateCustomButtonAppearance(doc, NO) annot_state: e_ptnormal app_state: nil];
            // Create 'SubmitForm' action. The action will be linked to the button.
            PTFileSpec *url = [PTFileSpec CreateURL: [doc GetSDFDoc] url: @"http://www.pdftron.com"];
            PTAction *button_action = [PTAction CreateSubmitForm: url];
            // Associate the above action with 'Down' event in annotations action dictionary.
            PTObj * annot_action = [[custom_pushbutton1 GetSDFObj] PutDict: @"AA"];
            [annot_action Put: @"D" obj: [button_action GetSDFObj]];
            [blank_page AnnotPushBack: custom_pushbutton1];
            
            // Add the page as the last page in the document.
            [doc PagePushBack: blank_page];
            
            // If you are not satisfied with the look of default auto-generated appearance
            // streams you can delete "AP" entry from the Widget annotation and set
            // "NeedAppearances" flag in AcroForm dictionary:
            //    doc.GetAcroForm().PutBool("NeedAppearances", true);
            // This will force the viewer application to auto-generate new appearance streams
            // every time the document is opened.
            //
            // Alternatively you can generate custom annotation appearance using ElementWriter
            // and then set the "AP" entry in the widget dictionary to the new appearance
            // stream.
            //
            // Yet another option is to pre-populate field entries with dummy text. When
            // you edit the field values using PDFNet the new field appearances will match
            // the old ones.
            
            //doc.GetAcroForm().PutBool("NeedAppearances", true);
            [doc RefreshFieldAppearances];
            
            [doc SaveToFile: @"../../TestFiles/Output/forms_test1.pdf" flags: 0];
            printf("Done.\n");
        }
        @catch (NSException *e)
        {
            NSLog(@"%@", e.reason);
            ret = 1;
        }
        
        //----------------------------------------------------------------------------------
        // Example 2:
        // Fill-in forms / Modify values of existing fields.
        // Traverse all form fields in the document (and print out their names).
        // Search for specific fields in the document.
        //----------------------------------------------------------------------------------
        @try
        {
            PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: @"../../TestFiles/Output/forms_test1.pdf"];
            [doc InitSecurityHandler];
            
            PTFieldIterator * itr = [doc GetFieldIterator];
            for(; [itr HasNext]; [itr Next])
            {
                NSString *cur_field_name = [[itr Current] GetName];
                // Add one to the count for this field name for later processing
                if ([field_names objectForKey: cur_field_name] != nil)
                {
                    int same_field_name_count = [[field_names objectForKey: cur_field_name] intValue] + 1;
                    [field_names setObject: [NSNumber numberWithInt: same_field_name_count] forKey: cur_field_name];
                }
                else
                {
                    [field_names setObject: @"1" forKey: cur_field_name];
                }
                
                printf("Field name: %s\n", [[[itr Current] GetName] UTF8String]);
                printf("Field partial name: %s\n", [[[itr Current] GetPartialName] UTF8String]);
                
                printf("Field type: ");
                PTFieldType type = [[itr Current] GetType];
                NSString *str_val = [[itr Current] GetValueAsString];
                
                switch(type)
                {
                    case e_ptcheck:
                        [[itr Current] SetValueWithBool: YES];
                        printf("Check box: Value = %s\n", [str_val UTF8String]);
                        break;
                    case e_ptbutton:
                        printf("Button\n");
                        break;
                    case e_ptradio:
                        printf("Radio button: Value = %s\n", [str_val UTF8String]);
                        break;
                    case e_pttext:
                    {
                        printf("Text\n");
                        // Edit all variable text in the document
                        [[itr Current] SetValueWithString: [@"This is a new value. The old one was: " stringByAppendingString: str_val]];
                    }
                        break;
                    case e_ptchoice: printf("Choice\n"); break;
                    case e_ptsignature: printf("Signature\n"); break;
                    default: break;
                }
                
                printf("------------------------------\n");
            }
            
            // Search for a specific field
            PTField *f = [doc GetField: @"employee.name.first"];
            if (f)
            {
                printf("Field search for %s was successful\n", [[f GetName] UTF8String]);
            }
            else
            {
                printf("Field search failed \n");
            }
            
            // Regenerate field appearances.
            [doc RefreshFieldAppearances];
            [doc SaveToFile: @"../../TestFiles/Output/forms_test_edit.pdf" flags: 0];
            printf("Done.\n");
        }
        @catch(NSException *e)
        {
            NSLog(@"%@", e.reason);
            ret = 1;
        }
        
        //----------------------------------------------------------------------------------
        // Sample: Form templating
        // Replicate pages and form data within a document. Then rename field names to make
        // them unique.
        //----------------------------------------------------------------------------------
        @try
        {
            // Sample: Copying the page with forms within the same document
            PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: @"../../TestFiles/Output/forms_test1.pdf"];
            [doc InitSecurityHandler];
            
            PTPage *src_page = [doc GetPage: 1];
            [doc PagePushBack: src_page];  // Append several copies of the first page
            [doc PagePushBack: src_page];     // Note that forms are successfully copied
            [doc PagePushBack: src_page];
            [doc PagePushBack: src_page];
            
            // Now we rename fields in order to make every field unique.
            // You can use this technique for dynamic template filling where you have a 'master'
            // form page that should be replicated, but with unique field names on every page.
            for (NSString* key in field_names)
            {
                RenameAllFields(doc, key, [[field_names valueForKey: key] intValue]);
            }
            
            [doc SaveToFile: @"../../TestFiles/Output/forms_test1_cloned.pdf" flags: 0];
            printf("Done.\n");
        }
        @catch(NSException *e)
        {
            NSLog(@"%@", e.reason);
            ret = 1;
        }
        
        //----------------------------------------------------------------------------------
        // Sample:
        // Flatten all form fields in a document.
        // Note that this sample is intended to show that it is possible to flatten
        // individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
        // that will automatically flatten all fields.
        //----------------------------------------------------------------------------------
        @try
        {
            PTPDFDoc *doc = [[PTPDFDoc alloc] initWithFilepath: @"../../TestFiles/Output/forms_test1.pdf"];
            [doc InitSecurityHandler];
            
            // Traverse all pages
            if (true) {
                [doc FlattenAnnotations: NO];
            }
            else // Manual flattening
            {
                PTPageIterator *pitr;
                for (pitr = [doc GetPageIterator: 1];
                     [pitr HasNext]; [pitr Next])
                {
                    PTPage *page = [pitr Current];
                    for (int i = (int)[page GetNumAnnots] - 1; i >= 0; --i)
                    {
                        PTAnnot *annot = [page GetAnnot: i];
                        if ([annot GetType] == e_ptWidget)
                        {
                            [annot Flatten: page];
                        }
                    }
                }
            }
            
            [doc SaveToFile: @"../../TestFiles/Output/forms_test1_flattened.pdf" flags: 0];
            printf("Done.\n");
        }
        @catch(NSException *e)
        {
            NSLog(@"%@", e.reason);
            ret = 1;
        }
        [PTPDFNet Terminate: 0];        
        return ret;
    }
}
```

{% endcode %}
{% endtab %}

{% tab title="Swift" %}
{% code lineNumbers="true" %}

```swift
//---------------------------------------------------------------------------------------
// Copyright (c) 2001-2019 by PDFTron Systems Inc. All Rights Reserved.
// Consult legal.txt regarding legal and license information.
//---------------------------------------------------------------------------------------

import PDFNet
import Foundation

//---------------------------------------------------------------------------------------
// This sample illustrates basic PDFNet capabilities related to interactive
// forms (also known as AcroForms).
//---------------------------------------------------------------------------------------

func RenameAllFields(doc: PTPDFDoc, name: String) {
    var itr: PTFieldIterator = doc.getFieldIterator(withName: name)
    var counter: Int = 0
    while itr.hasNext() {
        let f: PTField = itr.current()
        f.rename(name + ("\(counter)"))
        itr = doc.getFieldIterator(withName: name)
        counter += 1
    }
}

enum CheckStyle : Int {
    case e_tick
    case e_circle
    case e_cross
    case e_diamond
    case e_square
    case e_star
}

// Note: The visual appearance of check-marks and radio-buttons in PDF documents is
// not limited to CheckStyle-s. It is possible to create a visual appearance using
// arbitrary glyph, text, raster image, or path object. Although most PDF producers
// limit the options to the above 'standard' styles, using PDFNet you can generate
// arbitrary appearances.
func CreateCheckmarkAppearance(doc: PTPDFDoc, style: CheckStyle) -> PTObj {
    // Create a checkmark appearance stream ------------------------------------
    let build: PTElementBuilder = PTElementBuilder()
    let writer: PTElementWriter = PTElementWriter()
    writer.writerBegin(with: doc.getSDFDoc(), compress: true)
    writer.write(build.createTextBegin())
    
    var symbol: String
    switch style {
    case .e_circle:
        symbol = "\u{154}"
    case .e_diamond:
        symbol = "\u{165}"
    case .e_cross:
        symbol = "\u{65}"
    case .e_square:
        symbol = "\u{156}"
    case .e_star:
        symbol = "\u{110}"
    default:
        // e_tick
        symbol = "\u{64}"
    }
    
    let checkmark: PTElement = build.createTextRun(withFont: symbol, font: PTFont.create(doc.getSDFDoc(), type: e_ptzapf_dingbats, embed: false), font_sz: 1)
    writer.write(checkmark)
    writer.write(build.createTextEnd())
    
    let stm: PTObj = writer.end()
    stm.putRect("BBox", x1: -0.2, y1: -0.2, x2: 1, y2: 1)   // Clip
    stm.putName("Subtype", name: "Form")
    return stm
}

func CreateButtonAppearance(doc: PTPDFDoc, button_down: Bool) -> PTObj {
    // Create a button appearance stream ------------------------------------
    let build: PTElementBuilder = PTElementBuilder()
    let writer: PTElementWriter = PTElementWriter()
    writer.writerBegin(with: doc.getSDFDoc(), compress: true)
    
    // Draw background
    var element: PTElement = build.createRect(0, y: 0, width: 101, height: 137)
    element.setPathFill(true)
    element.setPathStroke(false)
    element.getGState().setFill(PTColorSpace.createDeviceGray())
    element.getGState().setFillColor(with: PTColorPt(x: 0.75, y: 0, z: 0, w: 0))
    writer.write(element)
    
    // Draw 'Submit' text
    writer.write(build.createTextBegin())
    do {
        let text = "Submit"
        element = build.createTextRun(withFont: text, font: PTFont.create(doc.getSDFDoc(), type: e_pthelvetica_bold, embed: false), font_sz: 12)
        element.getGState().setFillColor(with: PTColorPt(x: 0, y: 0, z: 0, w: 0))
        
        if button_down {
            element.setTextMatrix(with: PTMatrix2D(a: 1, b: 0, c: 0, d: 1, h: 33, v: 10))
        }
        else {
            element.setTextMatrix(with: PTMatrix2D(a: 1, b: 0, c: 0, d: 1, h: 30, v: 13))
        }
        writer.write(element)
    }
    writer.write(build.createTextEnd())
    
    let stm: PTObj = writer.end()
    
    // Set the bounding box
    stm.putRect("BBox", x1: 0, y1: 0, x2: 101, y2: 37)
    stm.putName("Subtype", name: "Form")
    return stm
}

func runInteractiveFormsTest() -> Int {
    return autoreleasepool {
        var ret: Int = 0
        
        
        //----------------------------------------------------------------------------------
        // Example 1: Programatically create new Form Fields and Widget Annotations.
        //----------------------------------------------------------------------------------
        do {
            try PTPDFNet.catchException {
                let doc: PTPDFDoc = PTPDFDoc()
                let blank_page: PTPage = doc.pageCreate(PTPDFRect(x1: 0, y1: 0, x2: 612, y2: 792)) // Create a blank new page and add some form fields.

                // Create new fields.
                let emp_first_name: PTField = doc.fieldCreate(with: "employee.name.first", type: e_pttext, field_value: "John", def_field_value: "")
                let emp_last_name: PTField = doc.fieldCreate(with: "employee.name.last", type: e_pttext, field_value: "Doe", def_field_value: "")
                let emp_last_check1: PTField = doc.fieldCreate(with: "employee.name.check1", type: e_ptcheck, field_value: "Yes", def_field_value: "")
                
                let submit: PTField = doc.fieldCreate("submit", type: e_ptbutton, field_value: PTObj())
                
                // Create page annotations for the above fields.
                
                // Create text annotations
                let annot1: PTWidget = PTWidget.create(doc.getSDFDoc(), pos: PTPDFRect(x1: 50, y1: 550, x2: 350, y2: 600), field: emp_first_name)
                let annot2: PTWidget = PTWidget.create(doc.getSDFDoc(), pos: PTPDFRect(x1: 50, y1: 450, x2: 350, y2: 500), field: emp_last_name)
                
                // Create a check-box annotation
                let annot3: PTWidget = PTWidget.create(doc.getSDFDoc(), pos: PTPDFRect(x1: 64, y1: 356, x2: 120, y2: 410), field: emp_last_check1)
                // Set the annotation appearance for the "Yes" state...
                annot3.setAppearance(CreateCheckmarkAppearance(doc: doc, style: .e_tick), annot_state: e_ptnormal, app_state: "Yes")
                
                // Create button annotation
                let annot4: PTWidget = PTWidget.create(doc.getSDFDoc(), pos: PTPDFRect(x1: 64, y1: 284, x2: 163, y2: 320), field: submit)
                // Set the annotation appearances for the down and up state...
                annot4.setAppearance(CreateButtonAppearance(doc: doc, button_down: false), annot_state: e_ptnormal, app_state: "")
                annot4.setAppearance(CreateButtonAppearance(doc: doc, button_down: true), annot_state: e_ptdown, app_state: "")
                
                // Create 'SubmitForm' action. The action will be linked to the button.
                let url = PTFileSpec.createURL(doc.getSDFDoc(), url: "http://www.pdftron.com")
                let button_action: PTAction = PTAction.createSubmitForm(url)
                
                // Associate the above action with 'Down' event in annotations action dictionary.
                let annot_action: PTObj = annot4.getSDFObj().putDict("AA")
                annot_action.put("D", obj: button_action.getSDFObj())
                
                blank_page.annotPushBack(annot1)   // Add annotations to the page
                blank_page.annotPushBack(annot2)
                blank_page.annotPushBack(annot3)
                blank_page.annotPushBack(annot4)
                
                doc.pagePushBack(blank_page)
                
                // Add the page as the last page in the document.
                // If you are not satisfied with the look of default auto-generated appearance
                // streams you can delete "AP" entry from the Widget annotation and set
                // "NeedAppearances" flag in AcroForm dictionary:
                //    doc.GetAcroForm().PutBool("NeedAppearances", true);
                // This will force the viewer application to auto-generate new appearance streams
                // every time the document is opened.
                //
                // Alternatively you can generate custom annotation appearance using ElementWriter
                // and then set the "AP" entry in the widget dictionary to the new appearance
                // stream.
                //
                // Yet another option is to pre-populate field entries with dummy text. When
                // you edit the field values using PDFNet the new field appearances will match
                // the old ones.
                
                //doc.getAcroForm().putBool("NeedAppearances", value: true)
                doc.refreshFieldAppearances()
                
                doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1.pdf").path, flags: 0)
                print("Done.")
            }
        } catch let e as NSError {
            print("\(e)")
            ret = 1
        }
        
        //----------------------------------------------------------------------------------
        // Example 2:
        // Fill-in forms / Modify values of existing fields.
        // Traverse all form fields in the document (and print out their names).
        // Search for specific fields in the document.
        //----------------------------------------------------------------------------------

        do {
            try PTPDFNet.catchException {
                let doc: PTPDFDoc = PTPDFDoc(filepath: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1.pdf").path)
                doc.initSecurityHandler()
                
                let itr: PTFieldIterator = doc.getFieldIterator()
                while itr.hasNext() {
                    print("Field name: \(itr.current().getName()!)")
                    print("Field partial name: \(itr.current().getPartialName()!)")
                    
                    print("Field type: ")
                    let type: PTFieldType = itr.current().getType()
                    let str_val = itr.current().getValueAsString()
                    
                    switch type {
                    case e_ptcheck:
                        itr.current().setValueWith(true)
                        print("Check box: Value = \(str_val!)")
                    case e_ptbutton:
                        print("Button")
                    case e_ptradio:
                        print("Radio button: Value = \(str_val!)")
                    case e_pttext:
                        print("Text")
                        // Edit all variable text in the document
                        itr.current()?.setValueWith("This is a new value. The old one was: \(str_val!)")
                    case e_ptchoice:
                        print("Choice")
                    case e_ptsignature:
                        print("Signature")
                    default:
                        break
                    }
                    
                    print("------------------------------")
                    itr.next()
                }
                
                // Search for a specific field
                if let f: PTField = doc.getField("employee.name.first") {
                    print("Field search for \(f.getName()!) was successful")
                }
                else {
                    print("Field search failed")
                }
                
                // Regenerate field appearances.
                doc.refreshFieldAppearances()
                doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test_edit.pdf").path, flags: 0)
                print("Done.")

            }
        } catch let e as NSError {
            print("\(e)")
            ret = 1
        }
        
        //----------------------------------------------------------------------------------
        // Sample: Form templating
        // Replicate pages and form data within a document. Then rename field names to make
        // them unique.
        //----------------------------------------------------------------------------------
        do {
            try PTPDFNet.catchException {
                // Sample: Copying the page with forms within the same document
                let doc: PTPDFDoc = PTPDFDoc(filepath: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1.pdf").path)
                doc.initSecurityHandler()
                
                let src_page: PTPage = doc.getPage(1)
                doc.pagePushBack(src_page)
                // Append several copies of the first page
                doc.pagePushBack(src_page)
                // Note that forms are successfully copied
                doc.pagePushBack(src_page)
                doc.pagePushBack(src_page)
                
                // Now we rename fields in order to make every field unique.
                // You can use this technique for dynamic template filling where you have a 'master'
                // form page that should be replicated, but with unique field names on every page.
                RenameAllFields(doc: doc, name: "employee.name.first")
                RenameAllFields(doc: doc, name: "employee.name.last")
                RenameAllFields(doc: doc, name: "employee.name.check1")
                RenameAllFields(doc: doc, name: "submit")
                
                doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1_cloned.pdf").path, flags: 0)
                print("Done.")
            }
        } catch let e as NSError {
            print("\(e)")
            ret = 1
        }
        
        //----------------------------------------------------------------------------------
        // Sample:
        // Flatten all form fields in a document.
        // Note that this sample is intended to show that it is possible to flatten
        // individual fields. PDFNet provides a utility function PDFDoc.FlattenAnnotations()
        // that will automatically flatten all fields.
        //----------------------------------------------------------------------------------
        do {
            try PTPDFNet.catchException {
                let doc: PTPDFDoc = PTPDFDoc(filepath: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1.pdf").path)
                doc.initSecurityHandler()
                
                // Traverse all pages
                if true {
                    doc.flattenAnnotations(false)
                } else { // Manual flattening
//                    let pitr: PTPageIterator = doc.getPageIterator(1)
//                    while pitr.hasNext() {
//                        let page: PTPage = pitr.current()
//                        if let annots: PTObj = page.getAnnots() {
//                            // Look for all widget annotations (in reverse order)
//                            var i: Int = Int(annots.size()) - 1
//                            while i >= 0 {
//                                if (annots.getAt(UInt(i)).get("Subtype").value().getName() == "Widget") {
//                                    let field: PTField = PTField(field_dict: annots.getAt(UInt(i)))
//                                    field.flatten(page)
//
//                                    // Another way of making a read only field is by modifying
//                                    // field's e_read_only flag:
//                                    //    field.SetFlag(Field::e_read_only, true);
//                                }
//                                i -= 1
//                            }
//                        }
//                        pitr.next()
//                    }
                }
                doc.save(toFile: URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]).appendingPathComponent("forms_test1_flattened.pdf").path, flags: 0)
                print("Done.")
            }
        } catch let e as NSError {
            print("\(e)")
            ret = 1
        }
        
        return ret
    }
}
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/ios/get-started/samples/interactiveformstest.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
