You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/ar/index.md
+84-13Lines changed: 84 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -468,9 +468,11 @@ class ViewModel {
468
468
```
469
469
470
470
<divclass="warning">
471
-
<h4>Task.detached عادةً خاطئ</h4>
471
+
<h4>Task و Task.detached نمط سيء</h4>
472
472
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` على الدالة بدلاً من ذلك.
474
476
</div>
475
477
476
478
<divclass="analogy">
@@ -609,24 +611,93 @@ func badIdea() async {
609
611
610
612
تجمع الخيوط التعاوني في Swift له خيوط محدودة. حجب واحد بـ `DispatchSemaphore` أو `DispatchGroup.wait()` أو استدعاءات مماثلة يمكن أن يسبب جموداً. إذا كنت تحتاج ربط كود متزامن وغير متزامن، استخدم `async let` أو أعد الهيكلة للبقاء غير متزامن بالكامل.
611
613
612
-
### إنشاء Tasks غير ضرورية
614
+
<divid="managedtasks">
615
+
616
+
### إنشاء مهام غير مُدارة
617
+
618
+
المهام التي تنشئها يدوياً بـ `Task { ... }` أو `Task.detached { ... }` غير مُدارة. بعد إنشاء مهام غير مُدارة، لا يمكنك التحكم بها. لا يمكنك إلغاؤها إذا تم إلغاء المهمة التي بدأتها منها. لا يمكنك معرفة إذا أنهت عملها، إذا ألقت خطأ، أو جمع قيمة الإرجاع. بدء مثل هذه المهمة يشبه رمي زجاجة في البحر آملاً أن توصل رسالتها لوجهتها، دون رؤية تلك الزجاجة مرة أخرى.
619
+
620
+
<divclass="analogy">
621
+
<h4>مبنى المكاتب</h4>
622
+
623
+
`Task` يشبه تكليف موظف بعمل. الموظف يتعامل مع الطلب (بما في ذلك الانتظار لمكاتب أخرى) بينما تستمر في عملك الفوري.
624
+
625
+
بعد إرسال العمل للموظف، ليس لديك وسيلة للتواصل معها. لا يمكنك إخبارها بالتوقف عن العمل أو معرفة إذا انتهت وما كانت نتيجة ذلك العمل.
626
+
627
+
ما تريده فعلاً هو إعطاء الموظف جهاز اتصال لاسلكي للتواصل معها أثناء تعاملها مع الطلب. بجهاز الاتصال، يمكنك إخبارها بالتوقف، أو يمكنها إخبارك عندما تواجه خطأ، أو يمكنها الإبلاغ عن نتيجة الطلب الذي أعطيتها إياه.
628
+
</div>
629
+
630
+
بدلاً من إنشاء مهام غير مُدارة، استخدم تزامن Swift للحفاظ على التحكم في المهام الفرعية التي تنشئها. استخدم `TaskGroup` لإدارة (مجموعة من) المهام الفرعية. Swift توفر عدة دوال `withTaskGroup() { group in ... }` للمساعدة في إنشاء مجموعات المهام.
613
631
614
632
```swift
615
-
// إنشاء Task غير ضروري
616
-
funcfetchAll() async {
617
-
Task { awaitfetchUsers() }
618
-
Task { awaitfetchPosts() }
633
+
funcdoWork() async {
634
+
635
+
// هذا سيرجع عندما ترجع جميع المهام الفرعية، تلقي خطأ، أو يتم إلغاؤها
636
+
let result =tryawaitwithThrowingTaskGroup() { group in
637
+
group.addTask {
638
+
tryawaitself.performAsyncOperation1()
639
+
}
640
+
group.addTask {
641
+
tryawaitself.performAsyncOperation2()
642
+
}
643
+
// انتظر واجمع نتائج المهام هنا
644
+
}
619
645
}
620
646
621
-
// أفضل - استخدم التزامن المنظم
622
-
funcfetchAll() async {
623
-
asynclet users =fetchUsers()
624
-
asynclet posts =fetchPosts()
625
-
await (users, posts)
647
+
funcperformAsyncOperation1() asyncthrows->Int {
648
+
return1
649
+
}
650
+
funcperformAsyncOperation2() asyncthrows->Int {
651
+
return2
652
+
}
653
+
```
654
+
655
+
لجمع نتائج المهام الفرعية للمجموعة، يمكنك استخدام حلقة for-await-in:
656
+
657
+
```swift
658
+
var sum =0
659
+
forawait result in group {
660
+
sum += result
626
661
}
662
+
// sum == 3
627
663
```
628
664
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
+
structContentView: View {
681
+
682
+
@Stateprivatevar 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 يعيد تشغيل المهمة
Copy file name to clipboardExpand all lines: src/en/index.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -471,7 +471,7 @@ class ViewModel {
471
471
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).
472
472
473
473
[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.
Copy file name to clipboardExpand all lines: src/es/index.md
+84-13Lines changed: 84 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -468,9 +468,11 @@ class ViewModel {
468
468
```
469
469
470
470
<divclass="warning">
471
-
<h4>Task.detached usualmente está mal</h4>
471
+
<h4>Task y Task.detached son un antipatrón</h4>
472
472
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.
474
476
</div>
475
477
476
478
<divclass="analogy">
@@ -609,24 +611,93 @@ func badIdea() async {
609
611
610
612
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.
611
613
612
-
### Crear Tasks innecesarios
614
+
<divid="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
+
<divclass="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.
613
631
614
632
```swift
615
-
// Creación innecesaria de Task
616
-
funcfetchAll() async {
617
-
Task { awaitfetchUsers() }
618
-
Task { awaitfetchPosts() }
633
+
funcdoWork() async {
634
+
635
+
// esto retornará cuando todos los subtasks retornen, lancen un error, o sean cancelados
636
+
let result =tryawaitwithThrowingTaskGroup() { group in
637
+
group.addTask {
638
+
tryawaitself.performAsyncOperation1()
639
+
}
640
+
group.addTask {
641
+
tryawaitself.performAsyncOperation2()
642
+
}
643
+
// espera y recoge los resultados de los tasks aquí
644
+
}
619
645
}
620
646
621
-
// Mejor - usa concurrencia estructurada
622
-
funcfetchAll() async {
623
-
asynclet users =fetchUsers()
624
-
asynclet posts =fetchPosts()
625
-
await (users, posts)
647
+
funcperformAsyncOperation1() asyncthrows->Int {
648
+
return1
649
+
}
650
+
funcperformAsyncOperation2() asyncthrows->Int {
651
+
return2
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
+
forawait result in group {
660
+
sum += result
626
661
}
662
+
// sum == 3
627
663
```
628
664
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
+
structContentView: View {
681
+
682
+
@Stateprivatevar 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
0 commit comments