¡Buena pregunta!
Como primer principio, siempre he organizado los archivos de mi aplicación en Xcode por funcionalidad .
Mira la captura de pantalla a continuación:
- ¿Cuánto costaría crear una aplicación móvil iOS como EatNow?
- ¿Qué es una buena práctica para alojar los Términos de servicio, la Política de privacidad por separado del producto (aplicación, sitio web), para que los abogados puedan actualizarlo fácilmente?
- Cómo desarrollar una aplicación de mensajería en tiempo real para iOS
- Cómo crear la animación de la aplicación de iPhone de AirBnB para el menú lateral en una aplicación nativa
- ¿Cuál es la mejor empresa de desarrollo de iOS en Canadá?
En la parte superior, puede ver dos archivos:
- Constants.swift, que contiene estructuras para todas las constantes estáticas utilizadas en la aplicación como “https://example.com/api” para la ubicación de la API REST.
- AppDelegate.swift, el punto de partida de su aplicación, ubicado lógicamente en la parte superior de la estructura de carpetas.
Luego está la carpeta API. No es parte de la interfaz de usuario, y no lo uso en todas las aplicaciones, porque estos archivos contienen código modular para trabajar con API. En esta aplicación en particular, hay una API para trabajar con el servicio REST y una API para trabajar con la base de datos local de Realm. Dicha API va entre el código de la IU y el código REST / Realm real, por lo que puedo llamar a métodos como “getArticlesWithCategory (category :)” desde la IU sin tener que escribir el código específico del Reino (como tratar con transacciones y manejo de errores). La carpeta API contiene una subcarpeta con Modelos (específicos del Reino), porque están estrechamente relacionados con las API mismas.
Luego, casi todas las demás carpetas son interfaces de usuario específicas. Cada interfaz de usuario tiene su propio archivo de clase Swift y un XIB. Cualquier interfaz de usuario que forme parte de otra interfaz de usuario, como el “Controlador de permisos de inserción” que forma parte del “Controlador de vista de artículo”, se estructura como una subcarpeta.
Llevo casi 8 años codificando aplicaciones y todavía estoy trabajando con XIB individuales en Storyboards repletos. Interface Builder ha tenido errores recientemente, por lo que trato de mantener baja la carga en mi sistema trabajando con XIB individuales. Además de la comodidad, los Storyboards no me ofrecen mucho, por lo que es igual de fácil trabajar con combos Swift / XIB.
Luego, cuanto más bajo llegue a la lista, más “generales” se volverán las clases. Hay una subclase para la barra de pestañas, una subclase para el controlador de navegación y un Controlador de vista de menú, en la aplicación que es un menú de hamburguesas, siempre presente, que tiene una subcarpeta para una celda de vista de tabla personalizada.
En los “Archivos de soporte” puede ver algunos subdirectorios, por ejemplo, extensiones. Si recuerdo correctamente, no podría usar CocoaPods para SWRevealController en ese momento, por eso se incluye como código fuente. No se muestra en la imagen, pero el proyecto que está viendo está dentro de un espacio de trabajo junto con el típico proyecto generado por CocoaPods.
Entonces, para resumir:
- Organice clases y XIB por funcionalidad, anidados por subfuncionalidad o sub-IU.
- El código similar a un marco que no es UI tiene sus propias carpetas, como API.
- Las modelos tienen sus propias carpetas.
- El código genérico de la interfaz de usuario, como la subclase UINavigationController, va más abajo en la lista de carpetas de la interfaz de usuario.
- Los archivos de soporte, como extensiones, utilidades y bibliotecas no controladas por la fuente van en su propia carpeta.
Para responder a sus preguntas adicionales:
- Pondría una vista personalizada junto a donde se usa, por ejemplo, con una celda de vista de tabla personalizada. Si realmente está haciendo algo genérico que no pertenece a una interfaz de usuario en particular, o se usa en varios lugares, le daría su propia subcarpeta en una carpeta de soporte. Sin embargo, tenga en cuenta que, dado que da la impresión de modularidad con dicha estructura, no debe acoplar la vista personalizada con ninguna parte de su aplicación.
- Veo que MVVM te confunde. Xcode, y el desarrollo de iOS, es Model-View-Controller (MVC) por defecto. Un modelo de vista generalmente vincula las propiedades de un modelo a la interfaz de usuario de una vista. Es popularizado por marcos como Angular o React, que tienen un enfoque completamente diferente de MVC. En cuanto al desarrollo de iOS, para usar MVVM, colocaría un ViewModel entre el Modelo y el Controlador de Vista, y lo usaría para (re) presentar los datos del Modelo al ViewController. Puede usar MVVM para separar mejor la lógica de decisión y la lógica de representación. He incluido un buen artículo al final de mi publicación de respuestas.
- Core Data normalmente no genera un ViewModel, genera clases de Modelo basadas en las propiedades que crea en sus archivos de Modelo. He descubierto que Core Data es lento y confuso, así que me mudé a Realm como mi marco de datos predeterminado hace mucho tiempo. ¡Deberías probarlo! Es más fácil trabajar con él, tiene un código más limpio y está estrechamente relacionado con sus clases de datos Swift comunes (en lugar de ese gigante de un NSManagedObject).
- Cuando se trata de marcos, evitaría escribir sus propios marcos si recién está comenzando. Hazlo por diversión, pero no intentes reinventar la rueda en un entorno de producción. Úselo para descubrir la mecánica de otros marcos y cómo toman decisiones. Cuando usa un bloque de código o mecanismo en particular, repetidamente en su código, lo pongo en una extensión, marco pequeño o clase de utilidad para que no se repita (principio DRY). Practique desacoplando su código, es decir, para no enredar todas las clases entre sí.
¡Feliz codificación!
Realm: Documentación de la plataforma móvil de Realm
MVVM: Introducción a MVVM