iOS 26 RC - UITextField duplicates first IME character when losing focus

Platform: iOS 26 RC / Xcode 26 RC Component: UIKit - UITextField

Description: When typing a Japanese character (or other IME input) as the first character in a UITextField and then losing focus (by pressing Enter or tapping elsewhere), the character is incorrectly duplicated. This issue only happens in iOS26 beta.

Steps to Reproduce:

  1. Create a UITextField with shouldChangeCharactersIn delegate
  2. Switch to Japanese keyboard
  3. Type "あ" (or any hiragana character)
  4. Press Enter or tap outside the text field
  5. Observe the character count becomes 2 instead of 1

Expected Result: Character count should remain 1

Actual Result: Character is duplicated, count becomes 2

Sample Code:

func shouldChangeText(
        in range: NSRange,
        replacementText string: String,
        maximumNumberOfCharacters: Int,
        regexValidation: String? = nil) -> (String, Bool) {
            
        guard let stringRange = Range(range, in: currentText) else {
            return (currentText, false)
        }
        if let regex = regexValidation,
            string != "", // delete key
            !string.room.checkPattern(regex) {
            return (currentText, false)
        }
        
        let changedText = currentText.replacingCharacters(in: stringRange, with: string)
        let allowChange = changedText.utf16.count <= maximumNumberOfCharacters
        print("=== stringRange: \(stringRange), currentText: \(currentText), replacementText: \(string) changedText: \(changedText), allowChange: \(allowChange) ===")
        guard !allowChange else {
            return (changedText, allowChange)
        }
        // Accept text deletion even if changedText count is more than maximumNumberCharacters
        guard !string.isEmpty else {
            return (changedText, true)
        }
        insert(text: string, maximumNumberOfCharacters: maximumNumberOfCharacters)
        return (currentText, allowChange)
    }

Log Comparison Details for Bug Report

Detailed Log Analysis: iOS 18.4 vs iOS 26 RC

Complete Test Scenario Log Comparison

Test Case: Type "あ" → Press Enter → Type "あ" → Delete → Type "A"


iOS 18.4 / Xcode 16 (Correct Behavior)

// Step 1: Type first "あ"
=== stringRange: 0[any]..<0[any], currentText: , replacementText: a changedText: a, allowChange: true ===
// Note: IME shows "a" first, then converts to "あ"

// Step 2: IME converts "a" to "あ"
=== stringRange: 0[utf16]..<1[utf16], currentText: あ, replacementText: あ changedText: あ, allowChange: true ===
// Result: Text = "あ", Count = 1 ✓

// Step 3: Press Enter (No additional delegate call - composition confirmed correctly)
// Result: Text = "あ", Count = 1 ✓

// Step 4: Delete "あ"
=== stringRange: 0[utf16]..<1[utf16], currentText: あ, replacementText:  changedText: , allowChange: true ===
// Result: Text = "", Count = 0 ✓

// Step 5: Type "A"
=== stringRange: 0[any]..<0[any], currentText: , replacementText: A changedText: A, allowChange: true ===
// Result: Text = "A", Count = 1 ✓

Final State iOS 18.4: Text = "A", UTF16 Count = 1 ✅


iOS 26 RC / Xcode 26 (Incorrect Behavior)

// Step 1: Type first "あ" (DIFFERENT: No initial "a" shown)
=== stringRange: 0[any]..<0[any], currentText: , replacementText: あ changedText: あ, allowChange: true ===
// Result: Text = "あ", Count = 1

// Step 2: Press Enter (BUG: Triggers duplicate character insertion)
=== stringRange: 1[utf16]..<1[utf16], currentText: あ, replacementText: あ changedText: ああ, allowChange: true ===
// Result: Text = "ああ", Count = 2 ❌ (Should be 1)

// Step 3: Type another "あ" (continues from duplicated state)
=== stringRange: 2[utf16]..<2[utf16], currentText: ああ, replacementText: あ changedText: あああ, allowChange: true ===
// Result: Text = "あああ", Count = 3 ❌ (Should be 2)

// Step 4: Delete (deletes from position 1, leaving first character)
=== stringRange: 0[utf16]..<1[utf16], currentText: あ, replacementText:  changedText: , allowChange: true ===
// Result: Text = "", Count = 0

// Step 5: Type "A"
=== stringRange: 0[any]..<0[any], currentText: , replacementText: A changedText: A, allowChange: true ===
// Result: Text = "A", Count = 1

Final State iOS 26: After first "あ" + Enter = "ああ", UTF16 Count = 2 ❌


Key Differences Summary

1. IME Composition Behavior

AspectiOS 18.4iOS 26 RC
Initial character inputShows "a" → converts to "あ"Directly shows "あ"
Range for conversion0..<1 (replacement)0..<0 (insertion)
Enter key behaviorNo delegate callTriggers duplicate insertion

2. Critical Bug Pattern

// iOS 26 Bug - When pressing Enter after first character:
Range: NSRange(location: 1, length: 0)  // Appending at position 1
CurrentText: "あ"                        // Already has the character
ReplacementString: "あ"                  // Same character again
Result: "ああ"                           // Duplication occurs

3. Range Index Notation Differences

  • iOS 18.4: Uses [any] for ASCII, [utf16] for IME characters
  • iOS 26: Uses [any] for initial IME input, [utf16] for subsequent operations

4. Delegate Call Sequence

iOS 18.4 - Correct Flow:

  1. Type "あ": 2 calls (a → あ conversion)
  2. Press Enter: 0 calls ✓
  3. Total: 2 delegate calls

iOS 26 RC - Incorrect Flow:

  1. Type "あ": 1 call
  2. Press Enter: 1 call (duplication bug) ❌
  3. Total: 2 delegate calls (but wrong parameters)

Impact Visualization

iOS 18.4 (Expected):
Type "あ" → [あ] (count: 1)
Press Enter → [あ] (count: 1) ✓
Type "い" → [あい] (count: 2) ✓

iOS 26 RC (Actual):
Type "あ" → [あ] (count: 1)
Press Enter → [ああ] (count: 2) ❌
Type "い" → [ああい] (count: 3) ❌

Root Cause Analysis

The iOS 26 RC appears to have changed how IME composition confirmation works:

  1. iOS 18.4: When focus is lost, the IME silently confirms the composition without triggering the delegate
  2. iOS 26 RC: When focus is lost, the IME triggers the delegate with incorrect parameters, treating the confirmation as a new character insertion

This suggests a regression in the IME state machine where the "composition confirmation" event is incorrectly mapped to a "character insertion" event.


This detailed log comparison clearly demonstrates the regression and should help Apple engineers quickly identify and fix the issue.

iOS 26 RC - UITextField duplicates first IME character when losing focus
 
 
Q