2 Punkte von GN⁺ 2024-03-06 | 1 Kommentare | Auf WhatsApp teilen
  • Paper läuft auf Apple-Plattformen als TextView-Editor auf Basis von TextKit 1; NSTextStorage, NSTextContainer, NSLayoutManager, TextView und ScrollView bilden gemeinsam die Bearbeitungserfahrung
  • NSAttributedString stellt Rich Text über eine Zeichenkette und bereichsbezogene Attribute dar; Paper trennt Meta-Attribute für die Markdown-Struktur von Stilattributen für die Bildschirmdarstellung
  • Stilaktualisierungen unterscheiden sich je nach Öffnen eines Dokuments, Textänderungen und Einstellungsänderungen; Attribute, die das Layout beeinflussen, werden in Transaktionen gebündelt, während dekorative Attribute ohne erneute Layoutberechnung aktualisiert werden
  • Die Eingabeleistung wird verbessert, indem geprüft wird, ob in der Nähe spezieller Markdown-Zeichen bearbeitet wird, um ein erneutes Parsen des gesamten Absatzes zu vermeiden; Strukturen wie Codeblöcke, die den Stil des gesamten Dokuments beeinflussen können, benötigen jedoch Sonderbehandlung
  • Kopieren und Einfügen funktioniert auf Basis mehrerer Datenrepräsentationen in UTI und Pasteboard; bei halböffentlichen UTI, die Apple nicht definiert hat, wie Markdown, können Prioritätsunterschiede zwischen Apps zu RTF-Konvertierungen und UX-Problemen führen

Apples TextView-Bearbeitungs-Stack

  • Paper basiert auf dem älteren TextKit 1-Framework; dieselben Konzepte und Abstraktionen existieren auch in TextKit 2 unverändert oder unter besseren APIs
  • NSTextView und UITextView unterscheiden sich, ihre APIs sind aber ähnlich genug, um sie als eine TextView-Familie zu behandeln
  • TextView ist eine große Komponente, die mit jedem OS-Release komplexer wird; die TextEdit-App besteht fast vollständig aus einer einzelnen TextView
  • Zentrale Schichten eines Editors

    • NSTextStorage
      • Speichert die ursprüngliche Textzeichenkette
      • Speichert Attribute als Zeichenkette-Wert-Paare, die Textbereichen zugeordnet sind
      • Löst Ereignisse bei Änderungen an Text und Attributen aus
    • NSTextContainer
      • Definiert Form und Größe des Bereichs, in den Glyphen passen
      • Meist rechteckig, beliebige Formen sind aber ebenfalls möglich
    • NSLayoutManager
      • Berechnet anhand der Attributbereiche in NSTextStorage Glyphengrößen und Abstände
      • Extrahiert Vektorglyphen aus Fonts und wandelt ein Zeichen in eine oder mehrere Glyphen um
      • Berechnet Anfang und Ende jeder Zeile, die Zeilenanzahl und die Gesamthöhe des Textes
    • TextView
      • Zeichnet das vom NSLayoutManager erzeugte Glyphenlayout
      • Synchronisiert die Höhe der View mit der aktuellen Texthöhe des Layouts
      • Verwaltet Eingabe, Auswahlbereich, Caret, Eingabeattribute, textContainerInset, Diktat, Kopieren und Einfügen, Rechtschreibprüfung usw.
    • ScrollView
      • Verwaltet den sichtbaren Bereich von TextView, Scrollen, Scrollleisten und Zoom
      • Kann zusätzlich zum textContainerInset von TextView ein eigenes contentInset haben
  • Unterschiede beim Scrollen in AppKit und UIKit

    • In AppKit enthält NSScrollView eine NSClipView und zwei NSScroller; die NSClipView enthält die NSTextView, sodass mehrere Klassen gemeinsam das Scrollverhalten erzeugen
    • In UIKit erbt UITextView von UIScrollView und enthält damit die Scrolllogik direkt
    • Wenn sich das Caret aus dem durch contentInset begrenzten sichtbaren Bereich herausbewegt, scrollt UITextView automatisch
    • Dass in iOS-Editoren zur nächsten Zeile gescrollt wird, wenn das Caret hinter die Tastatur gerät, liegt daran, dass das untere contentInset dynamisch auf die aktuelle Tastaturhöhe gesetzt wird

NSAttributedString und Attributabfragen

  • NSAttributedString ist die Grundlage der Rich-Text-Bearbeitung in Apples Frameworks und besteht aus zwei Elementen
    • Einer normalen Textzeichenkette
    • Zeichenkette-Wert-Attributpaaren, die Textbereichen innerhalb der Zeichenkette zugeordnet sind
  • Attribute werden vor allem für Styling verwendet, Entwickler können aber auch beliebige benötigte Zeichenkette-Wert-Paare hinzufügen
  • NSRange besteht aus location und length; NSMakeRange(10, 5) bedeutet einen Bereich von 5 Zeichen ab Position 10, also die Positionen 10 bis 14
  • Wenn dasselbe Attribut an derselben Position über mehrere Bereiche gesetzt ist, hat der zuletzt angewendete Bereich Vorrang
  • Attribute und Bereiche an einer bestimmten Position prüfen

    • Den Attributwert an einer bestimmten Position prüft man mit attribute:atIndex:effectiveRange:
    • Ist der Rückgabewert nil, existiert dieses Attribut nicht; andernfalls ist der Rückgabewert ein Attributwert, im Beispiel etwa ein NSFont- oder UIFont-Objekt
    • Übergibt man als letztes Argument einen NSRange-Zeiger, erhält man den Bereich, in dem dasselbe Attribut mit demselben Wert fortläuft, oder einen Leerbereich ohne dieses Attribut
    • Laut Dokumentation ist effectiveRange nicht zwingend der maximale Bereich und hängt von der Implementierung ab
    • Wird ein garantiert maximaler Bereich benötigt, sollte attribute:atIndex:longestEffectiveRange:inRange: verwendet werden
    • Es gibt auch eine Methode, um alle Attributkombinationen an einer bestimmten Position und den Bereich zu erhalten, in dem diese Kombination fortläuft
    • Zum Durchlaufen von Attributen innerhalb eines Bereichs kann enumerateAttribute:inRange:options:usingBlock: verwendet werden

Papers Markdown-Styling-Pipeline

  • Papers Styling funktioniert, indem spezielle, vom Framework definierte Attribute auf Textbereiche angewendet werden
  • Um die Textstruktur vor dem Styling zu erkennen, werden auch benutzerdefinierte Meta-Attribute verwendet
  • Meta-Attribute und Stilattribute

    • Meta-Attribute
      • Werden vom Markdown-Parser definiert, um einzelne Teile der Markdown-Syntax zu identifizieren
      • Sind rein semantische benutzerdefinierte Zeichenkette-Wert-Paare
      • Beeinflussen das visuelle Erscheinungsbild des Textes nicht
      • Man kann sie als vereinfachten AST für Markdown betrachten
    • Stilattribute
      • Sind visuelle Attribute, die auf die durch Meta-Attribute markierten Teile angewendet werden
      • Sind integrierte Zeichenkette-Wert-Paare, die AppKit und UIKit definieren
  • Ereignisse, die Attributaktualisierungen auslösen

    • Attribute werden mit dem Markdown-Text in NSTextStorage und mit Änderungen an Einstellungen synchronisiert, die den Text beeinflussen
    • Beim Öffnen eines Dokuments werden Meta-Attribute und Stilattribute vollständig aktualisiert
    • Bei Textänderungen werden Meta-Attribute und Stilattribute für die betroffenen Teile teilweise aktualisiert
    • Bei Einstellungsänderungen bleiben Meta-Attribute unverändert, nur Stilattribute werden vollständig aktualisiert
  • Aktualisierungsreihenfolge und Layoutkosten

    • Zuerst wird eine Textbearbeitungstransaktion gestartet, um Attributänderungen zu bündeln
    • Werden Attribute ohne Transaktion geändert, löst das jedes Mal eine teure Layout-Neuberechnung durch NSLayoutManager aus
    • Die Markdown-Zeichenkette wird geparst und in Fragmente zerlegt, die durch Meta-Attribute markiert werden; bei Einstellungsänderungen ändert sich die Markdown-Struktur nicht, daher wird dieser Schritt übersprungen
    • Visuelle Attribute, die Position oder Größe von Glyphen beeinflussen können, werden zuerst aktualisiert; NSParagraphStyle wird als wichtigstes Attribut behandelt, das Zeilen- und Absatzlayout beeinflusst
    • Nach Abschluss der Transaktion werden dekorative Attribute aktualisiert, die das Layout nicht beeinflussen
    • Dekorative Attribute entsprechen in Apples Terminologie Rendering-Attributen; sie befinden sich nicht in NSTextStorage, sondern in NSLayoutManager, und erkennen Transaktionen daher nicht
  • Eingabeattribute

    • Eingabeattribute (typing attributes) sind bei leerer Auswahl mit den Attributen an der Position vor dem Caret verbunden, bei nicht leerer Auswahl mit den Attributen am Anfang der Auswahl
    • Beim Eingeben eines Zeichens werden Eingabeattribute automatisch auf den neu eingefügten Text angewendet
    • In Markdown-Editoren sind sie weniger wichtig, weil sich der Stil aus der Markdown-Syntax ableitet
    • In Rich-Text-Editoren sind sie wichtiger, weil ein Stil am Caret haften bleibt, bis man ihn deaktiviert oder das Caret an eine andere Position bewegt
    • Papers Preview Mode bietet auch innerhalb eines Markdown-Editors eine Rich-Text-Bearbeitungserfahrung, bei der umschaltbare Eingabeattribute hervorgehoben werden

Eingabeleistung und Nutzung von Meta-Attributen

  • Die Trennung von Meta-, Layout- und dekorativen Attributen ist vorteilhaft, um bestimmte Editoränderungen schnell zu verarbeiten
  • Der Wechsel zwischen Light und Dark Mode aktualisiert nur dekorative Attribute und löst daher kein Layout aus, was sehr schnell ist
  • Einstellungsänderungen wie die Anpassung der Textgröße erfordern eine Neuberechnung des gesamten Dokumentlayouts, sind aber schneller als zusätzlich die gesamte Markdown-Struktur neu zu parsen
  • Optimierung der Markdown-Eingabe

    • Der wichtigste Leistungsfaktor eines Texteditors ist die Eingabegeschwindigkeit
    • Aufgrund der Eigenschaften von Markdown kann eine einzelne Textänderung den Stil eines gesamten Absatzes beeinflussen
    • Den gesamten Absatz bei jedem Tastendruck neu zu parsen und neu zu stylen ist technisch am korrektesten, kann in langen Absätzen aber die Bearbeitung verlangsamen
    • Paper verwendet einen Algorithmus, der anhand des nächsten eingegebenen Zeichens und der umgebenden Zeichen unterschiedliche Verhaltensweisen wählt
    • Wird ein spezielles Markdown-Zeichen eingegeben oder befinden sich spezielle Zeichen in der Nähe der Bearbeitungsposition, wird der gesamte Absatz aktualisiert
    • Andernfalls stützt sich Paper auf Eingabeattribute und beschleunigt den Editor in den meisten Eingabesituationen
  • Ausnahmen für Codeblöcke und Cache für Wertobjekte

    • Codeblöcke sind in Paper die einzige Markdown-Struktur über mehrere Absätze hinweg
    • In Dokumenten mit Codeblöcken kann ein einzelner Tastendruck den Stil des gesamten Dokuments beeinflussen
    • Paper ignoriert die Behandlung von Codeblöcken bei Dokumenten ab einer bestimmten Zeichenzahl, um für die Mehrheit der Nutzer, die sich nicht für Code interessieren, einen schnellen Editor zu erhalten
    • Diese Entscheidung macht Paper auch für entwicklernahe Nutzer nützlicher
    • Komplexe Attributwertobjekte werden bei jedem Tastendruck neu alloziert, ändern sich aber nicht, solange sich textbeeinflussende Einstellungen nicht ändern; sie werden daher gecacht und wiederverwendet
      • NSFont/UIFont
      • NSColor/UIColor
      • NSParagraphStyle
  • Funktionen, die Meta-Attribute verwenden

    • Formatierungs-Shortcuts
      • Um einen Toggle zu ermöglichen, muss die bestehende Stilinformation des ausgewählten Markdown-Texts bekannt sein
      • Umschließt die Auswahl denselben Stil vollständig, wird dieser Stil entfernt
      • Gibt es in der Auswahl keinen solchen Stil, wird der Stil hinzugefügt
      • Umschließt die Auswahl denselben Stil nur teilweise, wird der Stil auf den Auswahlbereich verschoben
      • Kollidierende Stile, die Absatztypen definieren, wie heading und blockquote, können nicht gemischt werden und müssen entfernt werden, bevor ein neuer Stil hinzugefügt wird
    • Kapitelnavigation
      • Beim Wechsel zur vorherigen oder nächsten Kapitelgrenze werden Meta-Attribute verwendet, um anhand der Caret-Position die heading zu finden
    • Outline
      • Alle headings werden durchlaufen; tippt man auf einen Outline-Eintrag, bewegt sich das Caret zu diesem Kapitel
    • Kapitel-Neuanordnung
      • Kapitel können in der Outline neu angeordnet werden
    • Formatkonvertierung
      • Um Markdown in RTF, HTML oder DOCX umzuwandeln, muss die Textstruktur bekannt sein
      • Da Paper keine externen Bibliotheken enthält, durchläuft es das vorab geparste Textmodell und erzeugt das Ausgabeformat

Textcontainer-Mathematik und Auswahlverhalten

  • Berechnung von Zeilenlänge und Rändern

    • Die zentrale Regel des Textcontainers besteht darin, die bevorzugte Zeilenlänge beizubehalten und den verbleibenden Platz auf die Insets beider Seiten aufzuteilen
    • Es gibt auch Situationen, in denen Symmetrie künstlich hergestellt werden muss, etwa wenn heading-Tags außerhalb des normalen Textflusses platziert werden
    • In diesem Fall wird der Textcontainer nach links verschoben und der Absatz mit NSParagraphStyle eingerückt
    • Ist genügend Platz vorhanden, werden die Ränder optisch möglichst symmetrisch gehalten
    • Gibt es keinen zusätzlichen Platz, wird die Symmetrie zugunsten der festgelegten Zeilenlänge gebrochen, jedoch nur solange noch rechtes Padding vorhanden ist
    • Bleibt kein Padding übrig, hat der Mindestabstand Vorrang vor der bevorzugten Zeilenbreite
    • Mit einer Kombination aus min und max lassen sich Ränder implementieren, die sich schrittweise einklappen
  • Auswahlanker

    • Textauswahl hat immer einen Ankerpunkt
    • Auf dem Mac ist beim Klicken und Ziehen der angeklickte Punkt die Referenz; überschreitet man diesen Punkt, kehrt sich die Richtung der Auswahlvergrößerung oder -verkleinerung um
    • Unter iOS wird beim Ziehen eines Auswahlgriffs die jeweils andere Seite zum Anker, und umgekehrt
    • Dieselbe Logik gilt auch beim Erweitern einer Auswahl per Tastatur
    • Mit Option+Pfeil links/rechts bewegt man sich zu Wortgrenzen; hält man zusätzlich Shift, wird wortweise ausgewählt
    • Auch wenn man nach einer Auswahl per Klicken und Ziehen die Auswahl per Tastatur weiter erweitert oder verkleinert, bleibt der zuerst angeklickte Punkt der Anker
  • Auswahl-Affinity

    • Auswahl-Affinity bestimmt an Zeilenumbruchgrenzen, ob der Einfügepunkt nach dem letzten Zeichen der vorherigen Zeile oder vor dem ersten Zeichen der nächsten Zeile erscheint
    • Bewegt man das Caret mit den Pfeiltasten, wechselt es an Leerraum um Zeilenumbrüche herum einfach die Zeile
    • Springt man per Shortcut ans Zeilenende, kann das Caret in derselben Zeile bleiben und rechts am Leerraum des Zeilenumbruchs haften
    • TextView führt ähnliche Auswahl-Affinity-Verhaltensweisen auch in anderen Situationen aus
  • Undo coalescing

    • Undo coalescing ist der Algorithmus, der entscheidet, wann eingegebener Text zu einer einzigen rückgängig machbaren Aktion zusammengefasst wird
    • TextView scheint einen einfachen Algorithmus zu verwenden, der Eingaben zusammenfasst, solange sie nicht durch eine andere Aktion unterbrochen werden
    • Auch wenn man zwischendurch pausiert und dann weitertippt, wird alles zu einem einzigen Undo zusammengefasst; auch Zeilenumbrüche unterbrechen das Coalescing nicht
    • Sublime bevorzugt es, beim Tippen einzelne Wörter als Undo-Einheiten zusammenzufassen, und teilt lange Wörter teils in kleinere Undo-Einheiten auf
    • Für dieses Verhalten gibt es keine richtige Antwort; verschiedene Editoren können unterschiedliche Strategien verfolgen

UTI, Pasteboard und Datenaustausch zwischen Apps

  • Uniform Type Identifiers

    • UTI ist ein hierarchisches System, in dem Datentypen sich wie von übergeordneten Datentypen erben bzw. diesen conform to
    • public.*-Typen werden von Apple definiert und identifizieren weit verbreitete Formate wie public.html und public.jpeg
    • Entwickler können eigene Identifier im Reverse-Domain-Name-Schema erstellen, um Kollisionen zu vermeiden
    • Der Vorteil des hierarchischen Systems ist, dass eine App, die alle Textformate verarbeiten kann, nur public.text deklarieren muss, statt jedes einzelne Format aufzulisten
    • Paper deklariert, dass es alle Textdateien öffnen kann, und kann Textformate wie .html und .rtf öffnen, auch ohne Highlighting
    • Dateien sind ein plattformübergreifendes Konzept, daher werden faktisch Dateiendungen als Identifier verwendet
    • Aus Kompatibilitätsgründen kann jede UTI eine oder mehrere verknüpfte Dateiendungen definieren
    • Markdown ist weit verbreitet, aber kein von Apple definiertes Format; daraus ergeben sich knifflige Fälle rund um eine halböffentliche UTI
  • Pasteboard und mehrere Repräsentationen

    • Apples Pasteboard ist ein Dictionary, das UTI auf serialisierte Text- oder Binärdaten abbildet
    • Mit dem Clipboard Viewer aus den Xcode Additional Tools kann man den Pasteboard-Inhalt in Echtzeit betrachten
    • Ein einzelner Kopiervorgang schreibt mehrere Repräsentationen derselben Daten gleichzeitig
    • Einige Apps verwenden aus Gründen der Abwärtskompatibilität auch ältere Nicht-UTI-Identifier wie NeXT Rich Text Format v1.0 pasteboard type
    • Editoren wählen in der Regel das reichhaltigste Format, das sie verarbeiten können
    • Paste and Match Style oder Paste as Plain Text in Rich-Text-Editoren erzwingt die Verwendung der Plain-Text-Repräsentation aus dem Pasteboard
    • Der auf eingefügten Text angewendete Stil stammt normalerweise aus den Eingabeattributen
    • Drag-and-drop basiert ebenfalls auf einem anderen Pasteboard
    • Für standardmäßiges Copy-paste wird das general pasteboard verwendet; für angepasste Interaktionen zwischen Apps können eigene Pasteboards erstellt werden
  • RTF und NSAttributedString

    • RTF ist im Grunde die serialisierte Form von NSAttributedString; umgekehrt ist NSAttributedString die Programmierschnittstelle zu RTF
    • TextView arbeitet auf NSTextStorage, einer Kindklasse von NSAttributedString, und ist daher grundsätzlich mit dem Pasteboard kompatibel
    • Inhalte können ohne zusätzlichen Code in das Pasteboard kopiert werden
  • App-übergreifende Probleme mit Markdown-UTI

    • Beim Kopieren und Einfügen zwischen Markdown-Editoren können Probleme auftreten, selbst wenn beide Apps Standardprotokolle implementieren
    • Exportiert der erste Editor Markdown als public.text und eine Rich-Text-Repräsentation als public.rtf, kann der zweite Editor nicht erkennen, dass es natives Markdown ist, und public.rtf auswählen
    • In diesem Fall kommt es zu unnötiger doppelter Konvertierung, und da Apps Markdown↔RTF unterschiedlich konvertieren, können kleine Formatierungsprobleme wie zusätzliche Zeilenumbrüche entstehen
    • Auch grundlegende Stilunterschiede zwischen Markdown und RTF können sichtbar werden
    • Damit es natürlich funktioniert, müssen beide Apps die UTI net.daringfireball.markdown exportieren und ihr Vorrang vor public.rtf geben
    • Paper versuchte, die Markdown-UTI zu exportieren, doch andere Apps schienen ihr keinen Vorrang vor Rich Text zu geben
    • Pages priorisiert net.daringfireball.markdown vor public.rtf, wandelt es jedoch nicht in Rich Text um, sondern fügt die ursprüngliche Markdown-Zeichenkette unverändert ein
    • Deshalb entfernte Paper die Markdown-UTI
  • Warum Paper RTF anbietet und iOS-Sharing

    • Paper bietet RTF an, damit Kopieren und Einfügen in Rich-Text-Editoren natürlich funktioniert
    • Als guter OS-Bürger sollte eine App mehrere Formate für die kopierten Daten bereitstellen, damit die empfangende App das reichhaltigste verarbeitbare Format auswählen kann
    • Kopiert man Markdown-Text aus Paper und fügt ihn in die Mail-App ein, erscheint er nicht als Markdown-Variante, sondern als ansprechend formatierter Rich Text
    • Die Teilen-Funktion von iOS ähnelt Copy-paste, ergänzt aber eine UI
    • Beim Teilen unter iOS exportiert eine App Daten in mehreren Formaten, und die empfangende App wählt das gewünschte Format aus
    • Anders als beim Pasteboard muss eine App explizit eine Share Extension mit eigener UI bereitstellen, um in der oberen App-Liste des iOS-Teilen-Menüs zu erscheinen

1 Kommentare

 
GN⁺ 2024-03-06
Hacker-News-Kommentare
  • Wirklich hervorragend. Als Einstieg in TextKit werde ich künftig wohl erst diesen Artikel lesen, noch vor https://www.objc.io/issues/5-ios7/getting-to-know-textkit/

  • Die TextEdit-App besteht fast vollständig aus einer einzigen TextView
    Das Windows-Pendant dazu sehe ich in WordPad auf Basis des RichEdit-Controls. Interessant ist außerdem, dass RTF im Grunde das Serialisierungsformat von NSAttributedString ist
    Beim RichEdit-Control von Windows ist es genauso, und tatsächlich scheint die Windows-Implementierung zuerst erschienen zu sein: https://en.wikipedia.org/wiki/Rich_Text_Format

  • Der Teil, dass dekorative Attribute außerhalb von Editiertransaktionen verarbeitet werden, ist etwas verwirrend. Es gab die Erklärung, dass sie „im NSLayoutManager selbst liegen und nicht in NSTextStorage, daher kennt er die Transaktion gar nicht“, aber dekorative Attribute wie Farben liegen normalerweise in NSTextStorage
    Meint der Autor, dass die auf Markdown-Zeichen angewendeten Farben über die Unterstützung für temporäre Attribute von NSLayoutManager umgesetzt werden? Das ist eine Funktion, die man normalerweise zum Einfärben falsch geschriebener Wörter nutzt; ich frage mich, welchem Zweck sie hier dient

    • Genau. Auch NSTextStorage kann Attribute enthalten, die temporären Attributen ähneln. In TextKit 2 nennt man sie Rendering-Attribute
      Der Vorteil temporärer Attribute ist, dass Änderungen viel schneller sind, als eine vollständige Transaktion von NSTextStorage auszulösen. In Paper ist zum Beispiel der Wechsel zwischen Light- und Dark-Mode sehr schnell
  • Wirklich ein guter Artikel, und für mich persönlich kam er genau zur richtigen Zeit, da ich gerade mit NSTextView arbeite
    Ich frage mich, wie man an die Informationen kommt, die nötig sind, um so einen Artikel zu schreiben. Code anderer Leute, schmerzhafte Erfahrung oder developer.apple.com?

    • Ich arbeite seit 9 Jahren an Paper und hatte in der Zeit viel Gelegenheit zu lernen, wie die gesamte Architektur funktioniert
  • Im Zeitalter von DOM-Dokumenten greift man selbst beim Blick auf Notion oder GitBook oft wieder auf Attributed Strings zurück, wenn es bei Text-Parsing und -Manipulation magische Dinge zu tun gibt
    Das ist eine wirklich elegante Struktur; ich verstehe nicht, warum sie so wenig bekannt ist. Der Artikel ist auch unglaublich gut

    • Falls es Beispiele gibt, würde ich gern mehr darüber lernen
    • Ich frage mich, ob es eine Web-Rich-Text-Editor-Komponente gibt, die Attributed Strings verwendet. Ich habe die DOM satt
  • Als jemand, der früher einmal versucht hat, einen Texteditor komplett von Grund auf selbst zu bauen, wäre so ein Artikel eine enorme Ressource gewesen

  • Ich nutze diese App wirklich gern. Sie hat alle anderen Markdown-Apps ersetzt, einschließlich Obsidian und iA Writer

    • Der Name Paper passt zwar, aber wenn ich mich richtig erinnere, gibt es unter den iOS-Apps mindestens zwei weitere Apps namens „Paper“
    • Interessant. Das sind genau die beiden Apps, die ich hauptsächlich zum Schreiben nutze; diese App sollte ich mir auch ansehen
  • Ich wünschte, es gäbe solche Dokumentation für mehr iOS-Komponenten

  • Schön, dass 2024 immerhin noch jemand Cocoa macht

  • Aus der Perspektive eines langjährigen Android-App-Entwicklers fand ich interessant, dass Apple die Dinge etwas anders und bedachter angeht
    Unter Android werden im Grunde alle Aufgaben rund um Layout und Rendering von der Klasse Layout und ihren Unterklassen erledigt, während TextView einen Teil der Editier- und Auswahllogik implementiert. Der einzige Unterschied zwischen EditText und TextView besteht darin, dass EditText die bereits in TextView vorhandenen Editierfunktionen aktiviert
    Das Problem an diesem etwas monolithischen Ansatz und der schwachen API ist, dass man blockiert wird, wenn man das Text-Rendering in einer App feiner steuern möchte. Wenn man zum Beispiel nach Abschluss des Layouts auf einzelne Glyphen zugreifen möchte, ist das nicht möglich