uso tips teclado para mac explorador cambiarse acostumbrarse macos core-data notifications daemon helpers

macos - teclado - tips para mac



¿Cómo lidiar con la arquitectura de la aplicación Mac OS X Helper/Main con respecto a los datos centrales, las preferencias compartidas y las notificaciones? (1)

Tengo algunas dudas arquitectónicas sobre un proyecto (aplicación Mac OS X) en el que estoy trabajando. Básicamente se compone de dos elementos: un daemon que se ejecuta en segundo plano recopilando algunos datos y un visor utilizado para representar los datos recopilados.

El daemon debe estar visible en la barra de estado (no en el icono de la base) e incluye un pequeño menú accesible a través de la barra de estado. Guarda datos en un almacén de datos central. Uno de los elementos del menú es un enlace que abre el visor . Cuando se abre este visor, debe comenzar una aplicación GUI normal que incluye un icono de dock y una barra de menú. El visor también se abre al abrir la aplicación en sí (haciendo doble clic en el icono).

Después de experimentar, descubrí que la mejor manera de lograr esta funcionalidad es creando dos aplicaciones, la principal que representa al espectador y una utilidad auxiliar que representa al daemon . Una de las razones por las que lo hice de esta manera es que no es posible cambiar entre los valores de LSUIElement instantáneamente para forzar el estado de daemon / viewer.

Ahora tengo algunas preguntas sobre esta arquitectura:

  • Tanto la aplicación de daemon como la del visor utilizan el mismo almacén de datos central para guardar y recuperar datos. Al tener una aplicación de subprocesos múltiples, NSManagedObjectContext que se necesitan varios objetos NSManagedObjectContext para sincronizar correctamente los datos. ¿Qué hay de tener múltiples aplicaciones utilizando el mismo almacén de datos central al mismo tiempo? ¿Esto es posible sin el riesgo de conflictos, bloqueos, etc.? ¿Cómo garantizo la consistencia?

  • El daemon siempre debe comenzar cuando el espectador comienza. Lo logré simplemente recorriendo todos los procesos abiertos y comprobando si el identificador del paquete del daemon está en la lista. De lo contrario, el daemon se inicia utilizando la aplicación NSWorkspace de launchApplication . Esto funciona bien Ahora cuando el usuario abandona el daemon, el espectador también debe detenerse. ¿Cuál es la mejor forma de que se notifique al espectador de la detención del daemon? Puedo verificar periódicamente los procesos activos y salir del visor si el daemon se ha ido, pero suena un poco extraño. Preferiría elegir algún tipo de notificación que enviaré cuando el espectador esté a punto de cerrar. Pero dado que esta notificación debe enviarse y capturarse entre aplicaciones, no sé qué servicio de notificación simple está disponible. ¿Alguna idea?

  • La aplicación es sandboxed, ya que se distribuirá en la Mac App Store. Iniciar aplicaciones con NSWorkspace de launchApplication hace que la aplicación de destino se ejecute en el mismo entorno de espacio aislado que la fuente, lo que creo que no es un problema en absoluto porque la ejecución de ambas aplicaciones en el mismo entorno se siente mejor y probablemente lo sea. Pero imagine este escenario: el daemon se inicia automáticamente al iniciar sesión (utilizando SMLoginItemSetEnabled ) y el usuario hace doble clic en Viewer.app. Como el daemon ya se está ejecutando (nuevamente, esto se comprueba mediante un bucle a través de procesos activos) no se iniciará. Ahora tenemos el daemon y el visor corriendo en diferentes sandboxes ¿verdad? ¿Esto causará algún problema con respecto a las preferencias, el almacén de datos central, etc.?

  • Me gustaría utilizar NSUserDefaults para la configuración básica, ¿puedo de alguna manera intercambiar esta información entre el daemon y el visor? Nuevamente, ambas aplicaciones tendrán diferentes identificadores de paquetes.

Gracias de antemano por su ayuda, ¡apreciado!


No hay una respuesta correcta para este problema, pero así es cómo lo abordaría:

Tanto la aplicación de daemon como la del visor utilizan el mismo almacén de datos central para guardar y recuperar datos.

Debido a que no es compatible el compartir un almacén de datos centrales entre procesos (hasta donde yo sé), haría que el daemon exponga un servicio XPC . En lugar de abrir la tienda Core Data en sí, el espectador usaría una NSXPCConnection para acceder a los datos a través del daemon.

Suponiendo que el espectador nunca se ejecuta sin el daemon, puede usar SMLoginItemSetEnabled , como mencionó en la pregunta, para registrar un servicio mach para el daemon, y luego conectarse a ese servicio.

Hay un código de muestra que repasa los detalles de la configuración que aparece here en el sitio web de Apple (resumen: el daemon debe estar en App.app/Contents/Library/LoginItems/daemon.bundle.id.app ), y es posible que también desee lea esta publicación de blog que analiza algunos requisitos adicionales impuestos por sandboxing (resumen: asegúrese de que su ID de equipo esté en el identificador de paquete del daemon).

El daemon siempre debe comenzar cuando el espectador comienza.

Todo configurado: una vez que registra el daemon con SMLoginItemSetEnabled , launchd lo iniciará (si es necesario) cuando el visor se conecte a su servicio XPC.

Ahora cuando el usuario abandona el daemon, el espectador también debe detenerse.

El espectador puede usar NSXPCConnection para averiguar cuándo se cierra el daemon. El daemon también puede usar SMLoginItemSetEnabled para SMLoginItemSetEnabled registro antes de que se cierre, para que no se vuelva a lanzar.

Me gustaría utilizar NSUserDefaults para la configuración básica, ¿puedo de alguna manera intercambiar esta información entre el daemon y el visor? Nuevamente, ambas aplicaciones tendrán diferentes identificadores de paquetes.

Use una suite para esto:

// To read or write: NSUserDefaults* suiteDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"com.example.app.shared"]; [suiteDefaults setObject:[NSDate date] forKey:@"launchTime"]; // Add the suite to -standardUserDefaults to make reading easier: NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; [defaults addSuiteNamed:@"com.example.app.shared"];

Para trabajar con sandboxing, el visor y el daemon deben compartir un grupo de aplicaciones. Incluso puede usar KVO para observar los cambios en las claves compartidas.