Skip to content

Commit 8ffbd48

Browse files
committed
Translate new content
1 parent e03e344 commit 8ffbd48

File tree

10 files changed

+757
-118
lines changed

10 files changed

+757
-118
lines changed

src/ar/index.md

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,11 @@ class ViewModel {
468468
```
469469

470470
<div class="warning">
471-
<h4>Task.detached عادةً خاطئ</h4>
471+
<h4>Task و Task.detached نمط سيء</h4>
472472

473-
فريق Swift يوصي بـ [Task.detached كملاذ أخير](https://forums.swift.org/t/revisiting-when-to-use-task-detached/57929). لا ترث الأولوية، القيم المحلية للمهمة، أو سياق الـ actor. معظم الوقت، `Task` العادية هي ما تريده. إذا كنت تحتاج عملاً مكثفاً على المعالج بعيداً عن الـ main actor، ضع علامة `@concurrent` على الدالة بدلاً من ذلك.
473+
المهام التي تجدولها بـ `Task { ... }` غير مُدارة. لا توجد طريقة لإلغائها أو معرفة متى تنتهي، إن انتهت أصلاً. لا توجد طريقة للوصول لقيمة الإرجاع أو معرفة إذا واجهت خطأ. في غالبية الحالات، سيكون من الأفضل استخدام مهام مُدارة بواسطة `.task` أو `TaskGroup`، [كما هو موضح في قسم "الأخطاء الشائعة"](#managedtasks).
474+
475+
[Task.detached يجب أن يكون ملاذك الأخير](https://forums.swift.org/t/revisiting-when-to-use-task-detached/57929). المهام المنفصلة لا ترث الأولوية، القيم المحلية للمهمة، أو سياق الـ actor. إذا كنت تحتاج عملاً مكثفاً على المعالج بعيداً عن الـ main actor، ضع علامة `@concurrent` على الدالة بدلاً من ذلك.
474476
</div>
475477

476478
<div class="analogy">
@@ -609,24 +611,93 @@ func badIdea() async {
609611

610612
تجمع الخيوط التعاوني في Swift له خيوط محدودة. حجب واحد بـ `DispatchSemaphore` أو `DispatchGroup.wait()` أو استدعاءات مماثلة يمكن أن يسبب جموداً. إذا كنت تحتاج ربط كود متزامن وغير متزامن، استخدم `async let` أو أعد الهيكلة للبقاء غير متزامن بالكامل.
611613

612-
### إنشاء Tasks غير ضرورية
614+
<div id="managedtasks">
615+
616+
### إنشاء مهام غير مُدارة
617+
618+
المهام التي تنشئها يدوياً بـ `Task { ... }` أو `Task.detached { ... }` غير مُدارة. بعد إنشاء مهام غير مُدارة، لا يمكنك التحكم بها. لا يمكنك إلغاؤها إذا تم إلغاء المهمة التي بدأتها منها. لا يمكنك معرفة إذا أنهت عملها، إذا ألقت خطأ، أو جمع قيمة الإرجاع. بدء مثل هذه المهمة يشبه رمي زجاجة في البحر آملاً أن توصل رسالتها لوجهتها، دون رؤية تلك الزجاجة مرة أخرى.
619+
620+
<div class="analogy">
621+
<h4>مبنى المكاتب</h4>
622+
623+
`Task` يشبه تكليف موظف بعمل. الموظف يتعامل مع الطلب (بما في ذلك الانتظار لمكاتب أخرى) بينما تستمر في عملك الفوري.
624+
625+
بعد إرسال العمل للموظف، ليس لديك وسيلة للتواصل معها. لا يمكنك إخبارها بالتوقف عن العمل أو معرفة إذا انتهت وما كانت نتيجة ذلك العمل.
626+
627+
ما تريده فعلاً هو إعطاء الموظف جهاز اتصال لاسلكي للتواصل معها أثناء تعاملها مع الطلب. بجهاز الاتصال، يمكنك إخبارها بالتوقف، أو يمكنها إخبارك عندما تواجه خطأ، أو يمكنها الإبلاغ عن نتيجة الطلب الذي أعطيتها إياه.
628+
</div>
629+
630+
بدلاً من إنشاء مهام غير مُدارة، استخدم تزامن Swift للحفاظ على التحكم في المهام الفرعية التي تنشئها. استخدم `TaskGroup` لإدارة (مجموعة من) المهام الفرعية. Swift توفر عدة دوال `withTaskGroup() { group in ... }` للمساعدة في إنشاء مجموعات المهام.
613631

614632
```swift
615-
// إنشاء Task غير ضروري
616-
func fetchAll() async {
617-
Task { await fetchUsers() }
618-
Task { await fetchPosts() }
633+
func doWork() async {
634+
635+
// هذا سيرجع عندما ترجع جميع المهام الفرعية، تلقي خطأ، أو يتم إلغاؤها
636+
let result = try await withThrowingTaskGroup() { group in
637+
group.addTask {
638+
try await self.performAsyncOperation1()
639+
}
640+
group.addTask {
641+
try await self.performAsyncOperation2()
642+
}
643+
// انتظر واجمع نتائج المهام هنا
644+
}
619645
}
620646

621-
// أفضل - استخدم التزامن المنظم
622-
func fetchAll() async {
623-
async let users = fetchUsers()
624-
async let posts = fetchPosts()
625-
await (users, posts)
647+
func performAsyncOperation1() async throws -> Int {
648+
return 1
649+
}
650+
func performAsyncOperation2() async throws -> Int {
651+
return 2
652+
}
653+
```
654+
655+
لجمع نتائج المهام الفرعية للمجموعة، يمكنك استخدام حلقة for-await-in:
656+
657+
```swift
658+
var sum = 0
659+
for await result in group {
660+
sum += result
626661
}
662+
// sum == 3
627663
```
628664

629-
إذا كنت بالفعل في سياق async، فضّل التزامن المنظم (`async let`، `TaskGroup`) على إنشاء `Task`s غير منظمة. التزامن المنظم يتعامل مع الإلغاء تلقائياً ويجعل الكود أسهل للفهم.
665+
يمكنك معرفة المزيد عن [TaskGroup](https://developer.apple.com/documentation/swift/taskgroup) في توثيق Swift.
666+
667+
#### ملاحظة حول المهام وSwiftUI.
668+
669+
عند كتابة واجهة مستخدم، غالباً تريد بدء مهام غير متزامنة من سياق متزامن. مثلاً، تريد تحميل صورة بشكل غير متزامن كاستجابة للمس عنصر واجهة. بدء مهام غير متزامنة من سياق متزامن غير ممكن في Swift. لهذا ترى حلولاً تتضمن `Task { ... }`، مما يُدخل مهاماً غير مُدارة.
670+
671+
لا يمكنك استخدام `TaskGroup` من مُعدّل SwiftUI متزامن لأن `withTaskGroup()` دالة async أيضاً وكذلك دوالها المرتبطة.
672+
673+
كبديل، SwiftUI يوفر مُعدّلاً غير متزامن يمكنك استخدامه لبدء عمليات غير متزامنة. المُعدّل `.task { }`، الذي ذكرناه سابقاً، يقبل دالة `() async -> Void`، مثالية لاستدعاء دوال `async` أخرى. متاح على كل `View`. يُفعّل قبل ظهور الواجهة والمهام التي ينشئها مُدارة ومرتبطة بدورة حياة الواجهة، مما يعني أن المهام تُلغى عندما تختفي الواجهة.
674+
675+
عودة لمثال اللمس-لتحميل-صورة: بدلاً من إنشاء مهمة غير مُدارة لاستدعاء دالة `loadImage()` غير المتزامنة من دالة `.onTap() { ... }` المتزامنة، يمكنك تبديل علَم عند لفتة اللمس واستخدام المُعدّل `task(id:)` لتحميل الصور بشكل غير متزامن عندما تتغير قيمة `id` (العلَم).
676+
677+
هنا مثال:
678+
679+
```swift
680+
struct ContentView: View {
681+
682+
@State private var shouldLoadImage = false
683+
684+
var body: some View {
685+
Button("اضغط هنا!") {
686+
// بدّل العلَم
687+
shouldLoadImage = !shouldLoadImage
688+
}
689+
// الـ View تدير المهمة الفرعية
690+
// تبدأ قبل عرض الواجهة
691+
// وتتوقف عندما تختفي الواجهة
692+
.task(id: shouldLoadImage) {
693+
// عندما تتغير قيمة العلَم، SwiftUI يعيد تشغيل المهمة
694+
guard shouldLoadImage else { return }
695+
await loadImage()
696+
}
697+
}
698+
}
699+
```
700+
</div>
630701

631702
</div>
632703
</section>

src/en/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,7 @@ class ViewModel {
471471
The tasks you schedule with `Task { ... }` are not managed. There is no way for you to cancel them or to know when they finish, if ever. There is no way to access their return value or to know if they encounter an error. In the majority of the cases, it will be better to use tasks managed by a `.task` or `TaskGroup`, [as explained in the "Common mistakes" section](#managedtasks).
472472

473473
[Task.detached should be your last resort](https://forums.swift.org/t/revisiting-when-to-use-task-detached/57929). Detached tasks don't inherit priority, task-local values, or actor context. If you need CPU-intensive work off the main actor, mark the function `@concurrent` instead.
474-
</div>
474+
</div>
475475

476476
<div class="analogy">
477477
<h4>Walking Through the Building</h4>

src/es/index.md

Lines changed: 84 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -468,9 +468,11 @@ class ViewModel {
468468
```
469469

470470
<div class="warning">
471-
<h4>Task.detached usualmente está mal</h4>
471+
<h4>Task y Task.detached son un antipatrón</h4>
472472

473-
El equipo de Swift recomienda [Task.detached como último recurso](https://forums.swift.org/t/revisiting-when-to-use-task-detached/57929). No hereda prioridad, valores task-local, ni contexto de actor. La mayoría de las veces, un `Task` regular es lo que quieres. Si necesitas trabajo intensivo de CPU fuera del main actor, marca la función `@concurrent` en su lugar.
473+
Los tasks que programas con `Task { ... }` no son gestionados. No hay forma de cancelarlos o saber cuándo terminan, si es que terminan. No hay forma de acceder a su valor de retorno o saber si encuentran un error. En la mayoría de los casos, será mejor usar tasks gestionados por `.task` o `TaskGroup`, [como se explica en la sección "Errores comunes"](#managedtasks).
474+
475+
[Task.detached debería ser tu último recurso](https://forums.swift.org/t/revisiting-when-to-use-task-detached/57929). Los tasks detached no heredan prioridad, valores task-local, ni contexto de actor. Si necesitas trabajo intensivo de CPU fuera del main actor, marca la función `@concurrent` en su lugar.
474476
</div>
475477

476478
<div class="analogy">
@@ -609,24 +611,93 @@ func badIdea() async {
609611

610612
El pool de hilos cooperativo de Swift tiene hilos limitados. Bloquear uno con `DispatchSemaphore`, `DispatchGroup.wait()`, o llamadas similares puede causar deadlocks. Si necesitas conectar código sync y async, usa `async let` o reestructura para quedarte completamente async.
611613

612-
### Crear Tasks innecesarios
614+
<div id="managedtasks">
615+
616+
### Crear tasks no gestionados
617+
618+
Los tasks que creas manualmente con `Task { ... }` o `Task.detached { ... }` no son gestionados. Después de crear tasks no gestionados, no puedes controlarlos. No puedes cancelarlos si el task desde el que los iniciaste es cancelado. No puedes saber si terminaron su trabajo, si lanzaron un error, o recoger su valor de retorno. Iniciar tal task es como tirar una botella al mar esperando que entregue su mensaje a su destino, sin volver a ver esa botella jamás.
619+
620+
<div class="analogy">
621+
<h4>El Edificio de Oficinas</h4>
622+
623+
Un `Task` es como asignar trabajo a un empleado. El empleado maneja la solicitud (incluyendo esperar a otras oficinas) mientras continúas con tu trabajo inmediato.
624+
625+
Después de enviar trabajo al empleado, no tienes medios para comunicarte con ella. No puedes decirle que deje el trabajo o saber si terminó y cuál fue el resultado de ese trabajo.
626+
627+
Lo que realmente quieres es darle al empleado un walkie-talkie para comunicarte con ella mientras maneja la solicitud. Con el walkie-talkie, puedes decirle que pare, o ella puede decirte cuando encuentre un error, o puede reportar el resultado de la solicitud que le diste.
628+
</div>
629+
630+
En lugar de crear tasks no gestionados, usa la concurrencia de Swift para mantener el control de los subtasks que creas. Usa `TaskGroup` para gestionar un (grupo de) subtask(s). Swift proporciona un par de funciones `withTaskGroup() { group in ... }` para ayudar a crear grupos de tasks.
613631

614632
```swift
615-
// Creación innecesaria de Task
616-
func fetchAll() async {
617-
Task { await fetchUsers() }
618-
Task { await fetchPosts() }
633+
func doWork() async {
634+
635+
// esto retornará cuando todos los subtasks retornen, lancen un error, o sean cancelados
636+
let result = try await withThrowingTaskGroup() { group in
637+
group.addTask {
638+
try await self.performAsyncOperation1()
639+
}
640+
group.addTask {
641+
try await self.performAsyncOperation2()
642+
}
643+
// espera y recoge los resultados de los tasks aquí
644+
}
619645
}
620646

621-
// Mejor - usa concurrencia estructurada
622-
func fetchAll() async {
623-
async let users = fetchUsers()
624-
async let posts = fetchPosts()
625-
await (users, posts)
647+
func performAsyncOperation1() async throws -> Int {
648+
return 1
649+
}
650+
func performAsyncOperation2() async throws -> Int {
651+
return 2
652+
}
653+
```
654+
655+
Para recoger los resultados de los tasks hijos del grupo, puedes usar un bucle for-await-in:
656+
657+
```swift
658+
var sum = 0
659+
for await result in group {
660+
sum += result
626661
}
662+
// sum == 3
627663
```
628664

629-
Si ya estás en un contexto async, prefiere la concurrencia estructurada (`async let`, `TaskGroup`) sobre crear `Task`s no estructurados. La concurrencia estructurada maneja la cancelación automáticamente y hace el código más fácil de razonar.
665+
Puedes aprender más sobre [TaskGroup](https://developer.apple.com/documentation/swift/taskgroup) en la documentación de Swift.
666+
667+
#### Nota sobre Tasks y SwiftUI.
668+
669+
Al escribir una UI, a menudo quieres iniciar tasks asíncronos desde un contexto síncrono. Por ejemplo, quieres cargar una imagen asíncronamente como respuesta a un toque en un elemento de UI. Iniciar tasks asíncronos desde un contexto síncrono no es posible en Swift. Por eso ves soluciones que involucran `Task { ... }`, lo cual introduce tasks no gestionados.
670+
671+
No puedes usar `TaskGroup` desde un modificador síncrono de SwiftUI porque `withTaskGroup()` es una función async también y lo mismo aplica para sus funciones relacionadas.
672+
673+
Como alternativa, SwiftUI ofrece un modificador asíncrono que puedes usar para iniciar operaciones asíncronas. El modificador `.task { }`, que ya mencionamos, acepta una función `() async -> Void`, ideal para llamar otras funciones `async`. Está disponible en cada `View`. Se activa antes de que la vista aparezca y los tasks que crea son gestionados y vinculados al ciclo de vida de la vista, lo que significa que los tasks se cancelan cuando la vista desaparece.
674+
675+
Volviendo al ejemplo de tocar-para-cargar-una-imagen: en lugar de crear un task no gestionado para llamar una función asíncrona `loadImage()` desde una función síncrona `.onTap() { ... }`, puedes alternar una bandera en el gesto de tap y usar el modificador `task(id:)` para cargar imágenes asíncronamente cuando el valor del `id` (la bandera) cambie.
676+
677+
Aquí hay un ejemplo:
678+
679+
```swift
680+
struct ContentView: View {
681+
682+
@State private var shouldLoadImage = false
683+
684+
var body: some View {
685+
Button("¡Haz clic!") {
686+
// alterna la bandera
687+
shouldLoadImage = !shouldLoadImage
688+
}
689+
// la View gestiona el subtask
690+
// se inicia antes de que la vista se muestre
691+
// y se detiene cuando la vista se oculta
692+
.task(id: shouldLoadImage) {
693+
// cuando el valor de la bandera cambia, SwiftUI reinicia el task
694+
guard shouldLoadImage else { return }
695+
await loadImage()
696+
}
697+
}
698+
}
699+
```
700+
</div>
630701

631702
</div>
632703
</section>

0 commit comments

Comments
 (0)