Entwicklung & Code
Asynchrone Programmierung – Teil 2: Koroutinen in C++ mit Boost.Asio
Mit dem Boost.Asio-Framework steht C++-Developern eine altbewährte Werkzeugsammlung zur Verfügung, die auch im modernen C++ noch ihre Berechtigung hat. Mit Kontexten, Exekutoren und Completion Tokens erlaubt sie es, asynchrone Programme nach unterschiedlichen Prinzipien sauber und effizient zu entwickeln. Callbacks Futures, spawn und yield_context gestatten auch einen an Koroutinen angelehnten Stil. Das hat der vorangegangene Artikel bereits gezeigt, der die Grundlagen von Boost.Asio vorgestellt hat.
Weiterlesen nach der Anzeige

Martin Meeser ist selbständiger Diplominformatiker (Uni) und bietet Dienstleistungen zum Thema Softwareentwicklung an: Individual-Software-Entwicklung, Beratung zu Prozessen und Schulungen. In zahlreichen Projekten betreute er bisher Kunden unter anderem aus den Bereichen Automotive, Finance, Raumfahrt, Radioastronomie und Medizintechnik.
Ab C++20 stehen nun aber Compiler-basierte stackless Koroutinen zur Verfügung. Damit kombiniert, spielt Boost.Asio seine vollen Stärken aus. Entwickler können jede Funktion oder Methode zu einer Koroutine ändern, indem sie eines der Schlüsselwörter co_yield, co_await odere co_return einsetzen. Der Compiler transformiert diese Funktion in eine Zustandsmaschine (Coroutine Frame), deren Ausführung an den durch co_await oder co_yield markierten Suspensionspunkten (Suspension Points) unterbrochen und später über einen std::coroutine_handle fortgesetzt wird. Der Coroutine Frame, der den Zustand speichert, liegt standardmäßig auf dem Heap, nicht auf dem Stack.
In Boost.Asio muss jede Koroutine eine Instanz vom Typ boost::asio::awaitable zurückgeben. awaitable kapselt den Rückgabe-Typen: awaitable bei einer Funktion ohne Rückgabewert, awaitable bei int, awaitable<:string/> bei String-Typen usw. (Listing 1).
boost::asio::awaitable async_void_sample()
{
co_return;
}
boost::asio::awaitable async_int_sample()
{
co_return 42;
}
boost::asio::awaitable<:string> async_string_sample()
{
co_return "Hello async";
Listing 1: Kapselung der Rückgabe-Typen mit awaitable
Für den Wechsel aus einem normalen Programmteil in einen Koroutinenteil dient die Funktion boost::asio::co_spawn. Sie erwartet drei Parameter:
- den Executor (oder
execution_contextausconvenience) auf dem die verzahnte oder parallele Ausführung der Koroutinen erfolgt - eine Instanz von
awaitable - ein CompletionToken vom Typ
detached, Funktions-Objekt oderuse_future
Weiterlesen nach der Anzeige
Mit detached läuft awaitable in einem eigenen Ablauf-Ast, ohne dass man das Ergebnis verarbeiten kann. Dieses wird oft in der main-Methode verwendet, um initial eine Koroutine aufzurufen (Listing 2).
int main()
{
boost::asio::io_context io_context;
// co_spawn mit CompletionToken Function-Object
boost::asio::co_spawn(io_context, async_int_sample(), [](std::exception_ptr,
int result)
{
std::cout << "async_int_sample() = " << result << std::endl;
});
// co_spawn mit CompletionToken use_future
std::future future = boost::asio::co_spawn(io_context,
async_string_sample(), boost::asio::use_future);
// co_spawn mit CompletionToken detached
boost::asio::co_spawn(io_context, async_caller(), boost::asio::detached);
io_context.run();
std::string s = future.get();
std::cout << "async_string_sample() = " << s << std::endl;
Listing 2: Beispiele von co_spawn mit awaitable zum Aufruf einer Koroutine.
Verwenden von co_await in Boost.Asio
Listing 3 zeigt die Verwendung von co_await. Bei dem Aufruf von awaitable mit co_await passiert Folgendes:
- Der Executor kann an dieser Stelle die Ausführung der Koroutine unterbrechen. Ob die Unterbrechung tatsächlich stattfindet, ist unbekannt und unerheblich.
- Unter Umständen führt der Executor andere Aktionen aus – verzahnt ( concurrent) auf einem Kontext mit einem Thread oder parallel auf einem Kontext mit mehreren Threads.
- An einem dem Entwickler unbekannten Zeitpunkt bringt der Exekutor
awaitableauf einem der Threads desexecution_contextzur Ausführung – auf welchem genau, ist unbekannt und unerheblich.
Sobald das Ergebnis von awaitable vorliegt, setzt der Exekutor die Koroutine an der Stelle fort, an der er sie verlassen hat.
boost::asio::awaitable async_callee(int i)
{
std::cout << "hello from awaitable, i=" << i << std::endl;
co_return i + 1;
}
boost::asio::awaitable async_caller()
{
int i = co_await async_callee(1);
// erzeugt ein awaitable, es wird aber nicht ausgeführt
boost::asio::awaitable aw = async_callee(2);
// awaitable kann nicht kopiert werden, move erforderlich
// co_await std::move(aw);
std::cout << "i=" << i << std::endl;
co_return;
}
// Ausgabe:
hello from awaitable, i=1
i=2
Listing 3: Beispiel für die Verwendung von co_await mit boost::asio::awaitable.
Der Ablauf aus Sicht der einzelnen Funktion ist also synchron – in dem Sinn, dass die Funktion stoppt, bis das Ergebnis von awaitable vorliegt. Es kommt aber nicht zu einer Blockierung des Threads, auf dem Entwickler ihre Funktion aufgerufen haben. Der Thread stand für andere Aktionen kooperativ zur Verfügung.
Entwickler können awaitable nur einmal verwenden. Wenn sie ein awaitable erzeugen, aber nicht mit co_await aufrufen, dann führt das Programm die Funktion nicht aus.
Listing 3 zeigt auch, wie der mit co_return zurückgegebene Wert durch den co_await-Ausdruck aus dem awaitable-Objekt extrahiert und einer Variablen in der aufrufenden Funktion zugewiesen wird. Dies ist ein sehr komfortabler Mechanismus, schließlich ist gar nicht bekannt, auf welches Thread async_callee zur Ausführung kommt.
Thread-übergreifendes Exception-Handling bei Koroutinen
Unbehandelte Execeptions, die innerhalb einer Koroutine auftreten, nimmt die aufrufende Koroutine co_await entgegen. Koroutinen fangen Exceptions also analog zur synchronen Funktionsweise ab, unabhängig davon, in welchem konkreten Thread die Exception auftrat. Listing 4 zeigt ein kurzes Beispiel.
#include
#include
boost::asio::awaitable async_ex_sample()
{
throw std::runtime_error{ "some exception" };
co_return;
}
int main()
{
boost::asio::thread_pool pool(4);
boost::asio::co_spawn(pool, []()->boost::asio::awaitable
{
try
{
co_await async_ex_sample();
}
catch (const std::exception& ex)
{
std::cout << ex.what() << std::endl;
}
co_return;
}, boost::asio::detached);
pool.join();
}
Listing 4: Thread-übergreifendes Exception-Handling.
Verwendung der Boost-Asio Funktionen mit CompletionToken use_awaitable
Listing 5 zeigt, wie Entwickler die asynchronen Funktionen der Boost.Asio-Bibliothek mit co_await verwenden: Dazu übergeben sie das CompletionToken use_awaitable als Parameter an die Methode async_wait des timer – Objektes, dementsprechend ist der Rückgabetyp der Funktion nun awaitable.
boost::asio::awaitable async_sample(
boost::asio::steady_timer timer,
boost::asio::ip::tcp::socket socket)
{
co_await timer.async_wait(boost::asio::use_awaitable);
char buf[4096];
std::size_t n = co_await socket.async_read_some(boost::asio::buffer(buf),
boost::asio::use_awaitable);
}
Listing 5: Beispiel für die Verwendung der Boost.Asio-Funktionen mit co_await und dem CompletionToken use_awaitable.
Asynchrone Schleifen
Ein weiterer Vorteil der Koroutinen ist, dass sich damit Schleifen im gewohnten for– oder while-Stil auch für asynchrone Abläufe formulieren lassen. Ohne Koroutinen müsste man die Iterationen in Callbacks auflösen oder komplexere Zustandsautomaten schreiben.
Der Code in Listing 6 liest einen Socket in einer Endlosschleife und schreibt die empfangenen Daten direkt wieder zurück – ein einfacher Echo-Server. Obwohl der Code wie eine normale Schleife aussieht, blockiert er keinen Thread. Jeder co_await-Ausdruck gibt die Kontrolle an den Exekutor zurück. Sobald Daten verfügbar sind oder ein Schreibvorgang abgeschlossen ist, läuft die Schleife an der unterbrochenen Stelle weiter – auf welchem Thread die Lese- und Schreibvorgänge ablaufen, ist unbekannt – dies wird durch den Exekutor bestimmt, den der Entwickler im co_spawn angegeben hat.
boost::asio::awaitable async_sample(boost::asio::ip::tcp::socket socket)
{
char buf[4096];
for (;;)
{
std::size_t n = co_await socket.async_read_some(
boost::asio::buffer(buf),
boost::asio::use_awaitable);
co_await boost::asio::async_write(
socket,
boost::asio::buffer(buf, n),
boost::asio::use_awaitable);
}
}
Listing 6: Beispiel für asynchrone for-Iteration.
Fehlerbehandlungen
Wie in vorangegangenen Beispielen bereits gezeigt, gibt es bei Koroutinen mehrere Möglichkeiten der Fehlerbehandlung:
- keine Fehlerbehandlung
- mit Try-Catch
- lokale Fehlervariable mit
boost::asio::redirect_errorals CompletionToken - als Teil eines Tupel-Rückgabewertes mit dem CompletionToken
boost::asio::as_tuple.
Das folgende Listing 7 zeigt entsprechende Beispiele:
boost::asio::awaitable errors_sample(boost::asio::ip::tcp::socket socket)
{
boost::asio::any_io_executor executor = co_await
boost::asio::this_coro::executor;
std::array buffer;
// 1. ohne Fehler-Behandlung
std::size_t n = co_await socket.async_read_some(boost::asio::buffer(buffer),
boost::asio::use_awaitable);
// 2. mit try-catch
try
{
std::size_t bytes_read = co_await
socket.async_read_some(boost::asio::buffer(buffer),
boost::asio::use_awaitable);
}
catch (const boost::system::system_error& e)
{
std::cerr << "Boost error during async_read_some: " << e.what() <<
std::endl;
}
// 3. mit redirect_error CompletionToken
boost::system::error_code ec;
std::size_t bytes_read2 = co_await
socket.async_read_some(boost::asio::buffer(buffer),
boost::asio::redirect_error(boost::asio::use_awaitable, ec));
if (ec)
{
std::cerr << "Error using error_code: " << ec.message() << std::endl;
}
// 4. mit as_tuple CompletionToken
auto [ec2, bytes_read3] = co_await
socket.async_read_some(boost::asio::buffer(buffer),
boost::asio::as_tuple(boost::asio::use_awaitable));
if (ec2)
{
std::cerr << "Error using as_tuple: " << ec2.message() << std::endl;
}
}
Listing 7: Beispiele für verschiedene Arten der Fehlerbehandlung in Boost.Asio.
Entwicklung & Code
Visual Studio Code 1.108: Profile importieren per Drag & Drop
Microsoft hat Visual Studio Code 1.108 veröffentlicht. Traditionell nutzt Microsoft den Dezember für Aufräumarbeiten statt für ein reguläres Release, doch in diesem Jahr gibt es offenbar zwölf statt elf Releases. Dabei haben die VS-Code-Entwickler die Tradition beibehalten, im Dezember Issues und Pull Requests aufzuräumen: Rund 6000 davon wurden geschlossen, und darüber hinaus sind einige Feature-Updates in das Dezember-Update eingeflossen.
Weiterlesen nach der Anzeige
Profile importieren per Drag & Drop
Es ist nun möglich, Einstellungsprofile per Drag & Drop einer .code-profile-Datei in VS Code zu ziehen, ähnlich wie bei einer .code-workspace-Datei zum Öffnen eines Workspace. Dann öffnet sich der Profile-Editor, der eine Vorschau zeigt und das Importieren des Profils ermöglicht. Das soll es vereinfachen, Profile mit Teammitgliedern zu teilen oder schnell eine neue Umgebung aufzusetzen.
Spezialisierte Skills für den KI-Agenten
Als experimentelles Feature lassen sich Agent Skills in GitHub Copilot verwenden. Entwicklerinnen und Entwickler können dem KI-Agenten dadurch neue Fähigkeiten beibringen und ihn beispielsweise mit domänenspezifischem Wissen füttern. Agent Skills bestehen aus Ordnern mit Anweisungen, Skripte und Ressourcen, die GitHub Copilot bei Bedarf laden kann. Sie sind ein offener Standard und wurden ursprünglich vom Unternehmen Anthropic entwickelt.
Zu den Vorteilen zählen laut Microsoft die Kombinierbarkeit mehrerer Skills für das Erstellen komplexer Workflows, die Spezialisierungsmöglichkeit für domänenspezifische Aufgaben ohne wiederholenden Kontext und das effiziente Laden ausschließlich relevanter Inhalte. Die Skills können zudem Wiederholungen vermeiden, da sie sich über alle Unterhaltungen hinweg verwenden lassen.
Das Erstellen und Verwenden von Agent Skills behandelt die VS-Code-Dokumentation im Detail. Dort kommen auch die Unterschiede zwischen den Agent Skills und den VS-Code-spezifischen benutzerdefinierten Anweisungen (Custom Instructions) zur Sprache.
Weiterlesen nach der Anzeige
Neuerungen in Agent-Sessions- und Chat-Ansicht
Die Agent-Sessions-Ansicht wurde überarbeitet: Sie bietet nun Keyboard-Zugang zu Aktionen wie „Archivieren“, „State lesen“ und „Session öffnen“, zeigt Informationen zu geänderten Dateien sowie zugehörigen Pull Requests für eine Session und kann aus den neuen Gruppenabschnitten heraus mehrere Sessions auf einmal archivieren.

Die Agent Sessions View bietet neue Funktionen.
(Bild: Microsoft)
Neuerungen gibt es auch im Chat. Unter anderem werden nun vorherige Chat-Sessions nicht automatisch wiederhergestellt, wenn VS Code neu gestartet wird. Allerdings lassen sich aus der Agent-Sessions-Steuerung frühere Chat-Sessions aufrufen. Dieses neue Verhalten lässt sich in der Einstellung chat.viewRestorePreviousSession anpassen.
Hausputz im Dezember
Im Rahmen des jährlichen Dezember-Housekeeping hat das VS-Code-Entwicklungsteam dieses Mal 5951 offene Issues und Pull Requests geschlossen. Für weitere 1203 Issues wurde eine Triage durchgeführt, sodass diese nicht länger unter „Unknown Type“ laufen.

Das VS-Code-Team hat aufgeräumt: 5951 offene Issues und PRs wurden im Dezember 2025 geschlossen.
(Bild: Microsoft)
Alle weiteren Informationen zu den Neuerungen in VS Code 1.108 teilt das Entwicklungsteam in der Ankündigung mit.
(mai)
Entwicklung & Code
Neu in .NET 10.0 [5]: Erweiterungsblöcke in C# 14.0
Die nachträgliche Erweiterbarkeit von Klassen um zusätzliche Methoden gibt es unter dem Namen Extension Methods bereits seit der C#-Sprachversion 3.0, die im Jahr 2007 zusammen mit .NET Framework 3.5 erschien. Dies ist sogar dann möglich, wenn die Klassen bereits an anderer Stelle kompiliert wurden, wie etwa die von Microsoft bereitgestellten Bibliotheken im .NET Framework.
Weiterlesen nach der Anzeige

Dr. Holger Schwichtenberg ist technischer Leiter des Expertennetzwerks www.IT-Visions.de, das mit 53 renommierten Experten zahlreiche mittlere und große Unternehmen durch Beratungen und Schulungen sowie bei der Softwareentwicklung unterstützt. Durch seine Auftritte auf zahlreichen nationalen und internationalen Fachkonferenzen sowie mehr als 90 Fachbücher und mehr als 1500 Fachartikel gehört Holger Schwichtenberg zu den bekanntesten Experten für .NET und Webtechniken in Deutschland.
Man kann mit Extension Methods aber lediglich eine Instanzmethode zu bestehenden Klassen ergänzen. So mussten Entwicklerinnen und Entwickler zwangsweise Konstrukte, die vom Namen her eigentlich Properties waren, leidigerweise als Methoden ausdrücken, siehe IsEmptyClassic() im nächsten Listing.
In der .NET-Klassenbibliothek gibt es aus diesem Grund einige Erweiterungsmethoden, die Namen besitzen, die man intuitiv als Property erwarten würde, darunter
Enumerable.Count()Queryable.Count()Enumerable.First()Enumerable.Last()
Folgender Beispielcode zeigt die klassischen Erweiterungsmethoden:
public static class StringExtensionClassic
{
public static string TruncateClassic(this string s, int count)
{
if (s == null) return "";
if (s.Length <= count) return s;
return s.Substring(0, count) + "...";
}
public static bool IsEmptyClassic(this string s)
=> String.IsNullOrEmpty(s);
}
In C# 14.0 bietet Microsoft nun mit dem neuen Block-Schlüsselwort extension eine verallgemeinerte Möglichkeit der Erweiterung bestehender .NET-Klassen, die Erweiterungsblöcke (Extension Blocks) oder Erweiterungsmitglieder (Extension Members) genannt werden.
Weiterlesen nach der Anzeige
Das Schlüsselwort extension muss Teil einer statischen, nicht generischen Klasse auf der obersten Ebene sein (also keine Nested Class). Nach dem Schlüsselwort extension deklariert man den zu erweiternden Typ (Receiver). Im nächsten Listing ist der Receiver die Klasse System.String (alternativ abgekürzt durch den eingebauten Typ string). Alle Methoden und Properties innerhalb des Extension-Blocks erweitern dann den hier genannten Receiver-Typ. Aktuell kann man in diesen Extension-Blöcken folgende Konstrukte verwenden (siehe nächstes Listing):
- Instanz-Methoden
- Statische Methoden
- Instanz-Properties
- Statische Properties
- Operatoren
Da es keine Instanzfelder (Fields) in Erweiterungsblöcken gibt, kann man mit Erweiterungsblöcken nicht den Zustand einer Klasse erweitern. Man kann nur bestehende Zustände lesen und verändern (sofern der Typ mutable ist).

Der Compiler meckert bei dem Versuch, eine Property mit Setter in einem Erweiterungsblock anzulegen.
Ein Erweiterungsblock darf beliebig viele Erweiterungsmitglieder enthalten. Eine Klasse darf mehrere Erweiterungsblöcke sowie zusätzlich auch klassische Extension Methods und andere statische Mitglieder enthalten. Das erlaubt Entwicklerinnen und Entwicklern, in bestehenden Klassen mit klassischen Erweiterungsmethoden nun noch die neuen Erweiterungsblöcke zu implementieren. Es darf auch mehrere Klassen mit Extension-Blöcken für einen Receiver-Typ geben.
Folgendes Codebeispiel zeigt die Erweiterungen für System.String mit C# 14.0:
public static class MyExtensions
{
// NEU in C# 14.0: // NEU in C# 14.0 Erweiterungsmitglieder (Schlüsselwort extension)
extension(System.String s) // <-- Receiver (Zielklasse).
{
///
/// Erweitern um eine Instanz-Methode (alternative Möglichkeit zur bisherigen Syntax)
///
public string Truncate(int count)
{
if (s == null) return "";
if (s.Length <= count) return s;
return s.Substring(0, count) + string.Dots;
}
///
/// NEU: Erweitern um eine Instanz-Eigenschaft nur mit Getter
///
public bool IsEmpty => String.IsNullOrEmpty(s);
///
/// NEU: Erweitern um eine Instanz-Eigenschaft mit Getter und Setter
///
public int Size
{
get { return s.Length; }
set
{
// Neuzuweisung geht nicht; Da Strings immutable sind, funktioniert die Setter-Logik so nicht!!!
if (value < s.Length) s = s.Substring(0, value);
if (value > s.Length) s = s + new string('.', value - s.Length);
}
}
///
/// NEU: Erweitern um eine statische Methode
///
public static string Create(int count, char c = '.')
{
return new string(c, count);
}
///
/// NEU: Erweitern um eine statische Instanz-Eigenschaft
///
public static string Dots => "...";
// NEU: Erweitern um eine Operatorüberladung
public static string operator *(string str, int i) // Operatorüberladung
{
return string.Concat(Enumerable.Repeat(str, i)); ;
}
// NEU: Operatorüberladung als Extension und neu ist auch, dass man ++ überladen kann
public void operator ++()
{
s = s + String.Dots; // Das funktioniert so nicht, da Strings immutable sind!!!
}
}
}
Folgender Code zeigt den Aufruf der Erweiterungsmethoden für die Klassen String und List:
public void Run()
{
CUI.Demo(nameof(CS14_ExtensionDemo) + ": String");
string s1 = "Hallo Holger";
Console.WriteLine($"Vorher: {s1}");
string s2 = s1.TruncateClassic(5);
Console.WriteLine($"Nach TruncateClassic(): {s1}"); // Hello...
Console.WriteLine($"IsEmptyClassic():{s2.IsEmptyClassic()}"); // false
string s3 = "Hallo Holger";
Console.WriteLine($"Vorher: {s3}");
string s4 = s3.Truncate(5);
Console.WriteLine($"Nach Truncate(): {s4}"); // Hello...
Console.WriteLine($"IsEmpty:{s4.IsEmpty}"); // false
string s5 = (s1 + "! ") * 3;
Console.WriteLine($"*3: {s5}"); // "Hallo Holger!Hallo Holger!Hallo Holger!"
string s6 = string.Create(5, '#');
Console.WriteLine($"string.Create(5, '#'): {s6}"); // "#####"
#region nicht möglich
CUI.H2("s1.Size = 5 --> das geht nicht, weil die Size Property versucht, die Zeichenkette neu zuzuweisen!");
// Das geht nicht, weil die Size Property versucht, die Zeichenkette neu zuzuweisen!
s1.Size = 5;
Console.WriteLine(s1); // "Hallo Holger" statt wie erwartet "Hallo"
s1++;
Console.WriteLine(s1); // "Hallo Holger" statt wie erwartet "Hallo Holger..."
#endregion
}

Ausgabe des Beispielcodes
(rme)
Entwicklung & Code
iOS: Apps können Mitteilungen geräuschlos ausliefern – ohne User-Kontrolle
Das Topangebot von Too Good to Go für leckere Donuts, die immer so schnell weg sind, oder die Information aus der Airthings-App, dass mit der Luft etwas nicht stimmt: Manche iOS-Mitteilungen (Notifications) scheinen wie verhext zu sein. Sie tauchen trotz der Tatsache, dass sie ganz normal in den Systemeinstellungen aktiviert sind, nur dann auf, wenn man das iPhone gerade aktiv bedient. Es gibt weder einen Auslieferungston noch, bei lautlosem Gerät, eine Vibration. In der Übersicht auf dem Sperrbildschirm sind sie ebenfalls zu sehen – nur eben erst dann, wenn man aktiv nachschaut. Das hat zur Folge, dass selbst vom Nutzer als wichtig angesehene Mitteilungen untergehen. Des Rätsels Lösung: Apple ermöglicht es Entwicklern, Mitteilungen auch „heimlich“ auszuliefern, eine Funktion im Code, die diese aktiv wählen müssen. Der Nutzer hat darüber dann allerdings keinerlei Kontrolle mehr, was viele nicht wissen.
Weiterlesen nach der Anzeige
Eine Konstante sorgt für Nerv
Seit iOS 15 können Developer für Mitteilungen nämlich auswählen, welchen „Interruption Level“ diese haben. Das Feature nennt sich UNNotificationInterruptionLevel, eine Konstante, die darlegt, wie wichtig eine Notification sein soll. Hier kann der Entwickler sie auf „Active“ stellen und damit ganz normal ausliefern – mit Aufleuchten des Bildschirms und Sound/Vibration. „Critical“ gibt die Mitteilung auch mit Ton aus, wenn das Gerät lautlos gestellt wurde. „TimeSensitive“ macht aus der Mitteilung eine „dringliche Mitteilung“, die auch einen Fokus durchbrechen kann.
Und dann gibt es noch „Passive“, also passiv. Und genau das ist die nervigste Variante für User, die informiert bleiben wollen: „Das System fügt die Benachrichtigung zur Benachrichtigungsliste hinzu, ohne den Bildschirm hell zu machen [falls das Gerät nicht verwendet wird] oder einen Ton abzuspielen.“ Das Problem betrifft auch die Apple Watch: Auch dort werden solche Mitteilungen lautlos ausgeliefert und landen nur in der Mitteilungsübersicht.
Entwickler nehmen Nutzern Einstellmöglichkeiten
Warum Developer für ihre Mitteilungen manchmal „Passive“ wählen, lässt sich schwer sagen. Eventuell denken diese, dass sie die Kunden nicht mit Mitteilungen überfrachten sollten. Manchmal ändert sich die Einstellung auch von App-Version zu App-Version – so geschehen bei erwähnter Airthings-App, die früher alle Warnungen sichtbar auslieferte. Dass damit dann möglicherweise wichtige Informationen schlicht verpasst werden, nehmen die Developer hin. User können wenig tun, sich nur bei den Entwicklern / App-Herstellern melden und diese bitten, doch wieder eine Änderung durchzuführen, damit Mitteilungen normal (UNNotificationInterruptionLevel auf „Active“) ausgeliefert werden.
Normal heißt dann, dass sich wie gewohnt über die Systemeinstellungen auswählen lässt, ob die Mitteilung einer App einen Benachrichtigungston und/oder eine Vibration hat – eine Sache von wenigen Sekunden. Entwickler, die fürchten, User mit zu vielen Mitteilungen zu überfrachten, können diesen erklären, wie sie hier gegebenenfalls vorgehen, statt ihnen die Entscheidung einfach abzunehmen. Und Apple sollte darüber nachdenken, ob sich die heimliche Auslieferung nicht über einen zentralen Knopf einfach abdrehen lassen könnte, wenn Nutzer dies wünschen. Hinzu kommt: Potenziell nervige Apps – von der Uber-Werbung bis zu Facebook – liefern ihre Mitteilungen natürlich niemals lautlos aus.
Weiterlesen nach der Anzeige
(bsc)
-
UX/UI & Webdesignvor 3 MonatenIllustrierte Reise nach New York City › PAGE online
-
Künstliche Intelligenzvor 3 MonatenAus Softwarefehlern lernen – Teil 3: Eine Marssonde gerät außer Kontrolle
-
Künstliche Intelligenzvor 3 Monaten
Top 10: Die beste kabellose Überwachungskamera im Test
-
UX/UI & Webdesignvor 3 MonatenSK Rapid Wien erneuert visuelle Identität
-
Entwicklung & Codevor 2 MonatenKommandozeile adé: Praktische, grafische Git-Verwaltung für den Mac
-
Künstliche Intelligenzvor 3 MonatenNeue PC-Spiele im November 2025: „Anno 117: Pax Romana“
-
Künstliche Intelligenzvor 3 MonatenDonnerstag: Deutsches Flugtaxi-Start-up am Ende, KI-Rechenzentren mit ARM-Chips
-
UX/UI & Webdesignvor 3 MonatenArndt Benedikt rebranded GreatVita › PAGE online
