CloneableJSON Documentation

Overview

CloneableJSON is a powerful data format that extends standard JSON to support complex data types like images, locations, and precise coordinate mappings. This guide shows you how to extract, process, and save data from utility pole and midspan measurement results.

CloneableJSON is a JSON wrapper that stores flexible data in our type wrapper AnyCloneableData. AnyCloneableData is heavily used when passing data between components in the core of our platform.

Reference

  • AnyCloneableData is a type-erased container to hold complex data types

  • CloneableImage stores UIImage data with file persistence capabilities

  • CloneableFileDataType is a protocol for file-based data types that have a UUID identifier

AnyCloneableData

Actual Data Structure from Pole Measurements

Based on the Pole_JSON_Formatter implementation, here's the exact structure of a pole measurement CloneableJSON:

{
  "high_accuracy": true,
  "pole_information": {
    "height": 35.5,
    "lean_angle": 2.1,
    "location": {
      "latitude": 40.7128,
      "longitude": -74.0060,
      "altitude": 10.5
    }
  },
  "attachments": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440001",
      "type": "attachment",
      "classification": "Transformer",
      "inventoryClass": {
        "name": "Transformer",
        "subcategories": [
          {
            "name": "Size",
            "value": "25 kVA"
          },
          {
            "name": "Type",
            "value": "Single Phase"
          }
        ]
      },
      "owner": "Utility Company A",
      "images": [
        {
          "imageId": "550e8400-e29b-41d4-a716-446655440002",
          "point": {
            "x": 256.5,
            "y": 384.2
          }
        }
      ],
      "related_task_id": "task_123",
      "height": 28.5,
      "distanceFromPoleTop": 7.0,
      "relatedSpans": ["550e8400-e29b-41d4-a716-446655440010"],
      "relatedGuys": ["550e8400-e29b-41d4-a716-446655440020"],
      "heading": 180
    }
  ],
  "images": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440003",
      "type": "pole",
      "image": "[CloneableImage UUID reference]",
      "referenceLine": {
        "bottom": {
          "id": "550e8400-e29b-41d4-a716-446655440004",
          "pixelCoordinates": {
            "x": 320.0,
            "y": 800.0
          },
          "worldCoordinates": {
            "x": 0.0,
            "y": 0.0,
            "z": 0.0
          }
        },
        "top": {
          "id": "550e8400-e29b-41d4-a716-446655440005",
          "pixelCoordinates": {
            "x": 320.0,
            "y": 100.0
          },
          "worldCoordinates": {
            "x": 0.0,
            "y": 0.0,
            "z": 35.5
          }
        }
      },
      "scalingData": {
        "pixelArray": [
          {
            "id": "550e8400-e29b-41d4-a716-446655440006",
            "pixelCoordinates": {
              "x": 200.5,
              "y": 450.2
            },
            "worldCoordinates": {
              "x": -2.1,
              "y": 0.8,
              "z": 15.5
            }
          }
        ]
      },
      "cameraTilt": 5.2,
      "predictedCameraTilt": 4.8,
      "wasAutoCaptured": false,
      "wasCapturedInSafeZone": true,
      "stickDistance": 12.5,
      "stickHeight": 8.0
    }
  ]
}

Understanding CloneableJSON

CloneableJSON uses a subscript-based access pattern that returns CloneableJSONValue enums. Starting with version 2.0, we've added convenient accessor methods to make working with the data much simpler.

Three Ways to Access Values

1. Safe Optional Access (Returns nil if wrong type)

2. Throwing Access (Throws descriptive errors)

3. Direct Enum Pattern Matching (Original method)

Available Accessor Properties and Methods

Optional Properties (return nil if wrong type):

  • .numberValue β†’ Double?

  • .stringValue β†’ String?

  • .boolValue β†’ Bool?

  • .dateValue β†’ Date?

  • .objectValue β†’ [String: CloneableJSONValue]?

  • .arrayValue β†’ [CloneableJSONValue]?

  • .isUndefined β†’ Bool (true if value is undefined)

Throwing Methods (throw JSONError if wrong type):

  • .getNumber() β†’ Double

  • .getString() β†’ String

  • .getBool() β†’ Bool

  • .getDate() β†’ Date

  • .getObject() β†’ [String: CloneableJSONValue]

  • .getArray() β†’ [CloneableJSONValue]

Helper Properties:

  • .typeDescription β†’ String (returns current type: "object", "array", "string", "number", etc.)

JSONError Types

Working with Attachments

Extracting Attachment Data

Extracting Inventory Classifications

Working with Images

Extracting and Saving Images

Alternative: Using AnyCloneableData Extension

Working with Scaling Data

Working with CloneableImage Directly

Advanced Image Operations

Simple JSON String Export

CloneableJSON provides a built-in method to convert to standard JSON string:

The getJSONValue() method automatically:

  • Converts CloneableImage objects to UUID strings (via getJSONValue() method)

  • Converts CloneableFileDataType objects to UUID strings

  • Converts CloneableNumber to standard JSON numbers

  • Returns pretty-printed, sorted JSON string

  • Preserves complete nested data structure

  • Handles undefined values as null

Schema Support

CloneableJSON supports optional schema validation:

Getting All File Data Values

Error Handling Best Practices

When using the throwing accessor methods, you can handle specific error cases:

Best Practices

  1. Use optional accessors for exploratory code - When you're not sure if a value exists or what type it is

  2. Use throwing accessors for production code - When you expect certain data to be present and want clear error messages

  3. Check .isUndefined before accessing nested values - To avoid unnecessary operations

  4. Use .typeDescription for debugging - To understand what type of value you're dealing with

  5. Prefer the convenience accessors - They're cleaner and more Swift-like than manual enum matching

  6. Handle CloneableImage download scenarios - Images may need to be downloaded from backend

  7. Use CloneableImage's built-in file operations - For saving and loading images efficiently

  8. Import UIKit when working with images - CloneableImage uses UIImage which requires UIKit

Quick Reference

Your Original Problem - Now Solved!

Last updated