2014-10-20 13 views
15

Nelle ultime settimane ho scritto un'applicazione mac in modo rapido, sia per accedere alla programmazione mac che per esercitarsi rapidamente quando ci trasferiamo sul mio posto di lavoro. Attualmente sto cercando di ottenere del codice funzionante per aggiungere la mia applicazione come applicazione "Avvio all'avvio" personalizzando il codice gentilmente fornito su BDungan's blogSwift - avvio di un'applicazione Mac all'avvio

Finora dopo aver incasinato per molte ore ho trovato il seguente:

func itemRefInLoginItems() -> LSSharedFileListItemRef? 
{ 
    var itemRef: LSSharedFileListItemRef? = nil 
    var itemURL: Unmanaged<CFURLRef>? 

    let appURL = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath) 


    if let loginItemsRef = LSSharedFileListCreate(kCFAllocatorDefault,kLSSharedFileListSessionLoginItems.takeRetainedValue(),NSMutableDictionary()) { 

     var unretainedLoginItemsRef = loginItemsRef.takeUnretainedValue() 

     if var loginItems = LSSharedFileListCopySnapshot(unretainedLoginItemsRef, nil) { 

      for item in (loginItems.takeRetainedValue() as NSArray) { 

       let currentItemRef = item as LSSharedFileListItemRef 

       var outRef: FSRef 
       if (LSSharedFileListItemResolve(currentItemRef, 0, &itemURL, nil) == noErr) { 

        if (appURL?.isEqual(itemURL?.takeRetainedValue()) != nil) { //PROBLEM 1 

         itemRef = currentItemRef 
        } 
       } 
      } 
     } 
    } 

    return itemRef 
} 

func isLaunchAtStartup() -> Bool { 

    let itemRef = self.itemRefInLoginItems() 
    return itemRef != nil 
} 

func makeLaunchAtStartup() { // Compile seems to fall down on this line... 

    if !self.isLaunchAtStartup() { 

     let loginItemsRef = LSSharedFileListCreate(kCFAllocatorDefault, kLSSharedFileListSessionLoginItems.takeRetainedValue(), NSMutableDictionary()) 

     let appURL = NSURL(fileURLWithPath: NSBundle.mainBundle().bundlePath) as CFURLRef 
     let itemRef = LSSharedFileListInsertItemURL(loginItemsRef.takeRetainedValue(), kLSSharedFileListItemLast.takeRetainedValue(), nil, nil, appURL, nil, nil) 
    } 
} 

Tuttavia, sto riscontrando due problemi.

Problema 1

Swift non vuole che io a confrontare un NSURL ad un CFURLRef ... per ora sono andato con un suggerimento Xcode solo per ottenere l'applicazione in esecuzione, ma sono sicuro al 100% che non sta facendo quello che penso sia. (vedi // PROBLEMA 1).

In ogg-c sembra che il ponte libero tra NSURL e CFURLRef (o CFURL) sia consentito, tuttavia nel tentativo di lanciare, cast condizionale o qualsiasi varietà di rapido come (Inserisci carattere corretto qui) si avvicina al mio codice inevitabilmente t costruire. Ottengo errori come:

non gestito non è un sottotipo di NSURL: if appURL as Unmanaged<CFURLRef> == itemURL

e.t.c.

Problema 2

Anche se questo codice dà attualmente non avvisi o errori ... quando si cerca di compilare ottengo un Command failed due to signal: Segmentation fault: 11, che per essere sinceri ... è oltre me.

risposta

11

Sono riuscito a ottenere un'implementazione funzionante di questo basato sull'approccio Objective C di Brian Dunagan. Ho anche eseguito il tuo problema di errore del segmento di compilatore, ma questo è stato causato dal tentativo di cast di tipi non validi; ottenere i tipi giusti risolve il problema.

Non è stato possibile ottenere kLSSharedFileListItemLast per restituire correttamente l'ultimo riferimento all'elemento file poiché causerebbe sempre un errore di seg. Per ovviare a questo problema ho modificato la funzione itemReferencesInLoginItems per restituire una tupla di riferimenti agli elementi.

Il primo elemento nella tupla è il riferimento dell'applicazione esistente se esiste, il secondo elemento è l'ultimo riferimento della lista. Utilizzando questo approccio possiamo evitare di fare affidamento su kLSSharedFileListItemLast.

Ecco il codice, sentitevi liberi di usarlo! Mi piacerebbe sapere se c'è un modo per far funzionare kLSSharedFileListItemLast.

func applicationIsInStartUpItems() -> Bool { 
    return (itemReferencesInLoginItems().existingReference != nil) 
} 

func itemReferencesInLoginItems() -> (existingReference: LSSharedFileListItemRef?, lastReference: LSSharedFileListItemRef?) { 
    var itemUrl : UnsafeMutablePointer<Unmanaged<CFURL>?> = UnsafeMutablePointer<Unmanaged<CFURL>?>.alloc(1) 
    if let appUrl : NSURL = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath) { 
     let loginItemsRef = LSSharedFileListCreate(
      nil, 
      kLSSharedFileListSessionLoginItems.takeRetainedValue(), 
      nil 
     ).takeRetainedValue() as LSSharedFileListRef? 
     if loginItemsRef != nil { 
      let loginItems: NSArray = LSSharedFileListCopySnapshot(loginItemsRef, nil).takeRetainedValue() as NSArray 
      println("There are \(loginItems.count) login items") 
      let lastItemRef: LSSharedFileListItemRef = loginItems.lastObject as LSSharedFileListItemRef 
      for var i = 0; i < loginItems.count; ++i { 
       let currentItemRef: LSSharedFileListItemRef = loginItems.objectAtIndex(i) as LSSharedFileListItemRef 
       if LSSharedFileListItemResolve(currentItemRef, 0, itemUrl, nil) == noErr { 
        if let urlRef: NSURL = itemUrl.memory?.takeRetainedValue() { 
         println("URL Ref: \(urlRef.lastPathComponent)") 
         if urlRef.isEqual(appUrl) { 
          return (currentItemRef, lastItemRef) 
         } 
        } 
       } else { 
        println("Unknown login application") 
       } 
      } 
      //The application was not found in the startup list 
      return (nil, lastItemRef) 
     } 
    } 
    return (nil, nil) 
} 

func toggleLaunchAtStartup() { 
    let itemReferences = itemReferencesInLoginItems() 
    let shouldBeToggled = (itemReferences.existingReference == nil) 
    let loginItemsRef = LSSharedFileListCreate(
     nil, 
     kLSSharedFileListSessionLoginItems.takeRetainedValue(), 
     nil 
     ).takeRetainedValue() as LSSharedFileListRef? 
    if loginItemsRef != nil { 
     if shouldBeToggled { 
      if let appUrl : CFURLRef = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath) { 
       LSSharedFileListInsertItemURL(
        loginItemsRef, 
        itemReferences.lastReference, 
        nil, 
        nil, 
        appUrl, 
        nil, 
        nil 
       ) 
       println("Application was added to login items") 
      } 
     } else { 
      if let itemRef = itemReferences.existingReference { 
       LSSharedFileListItemRemove(loginItemsRef,itemRef); 
       println("Application was removed from login items") 
      } 
     } 
    } 
} 
+1

Che dopo sandbox Abilitato ? – ak2g

4

risposta incredibile, ma ti sei dimenticato un if per verificare evitare che un errore da unwraping un valore vuoto se non ci sono elementi esistono

Qui è una soluzione rapida per la sola funzione, spero che aiuta qualcuno

func itemReferencesInLoginItems() -> (existingReference: LSSharedFileListItemRef?, lastReference: LSSharedFileListItemRef?) { 
    var itemUrl : UnsafeMutablePointer<Unmanaged<CFURL>?> = UnsafeMutablePointer<Unmanaged<CFURL>?>.alloc(1) 
    if let appUrl : NSURL = NSURL.fileURLWithPath(NSBundle.mainBundle().bundlePath) { 
     let loginItemsRef = LSSharedFileListCreate(
      nil, 
      kLSSharedFileListSessionLoginItems.takeRetainedValue(), 
      nil 
      ).takeRetainedValue() as LSSharedFileListRef? 
     if loginItemsRef != nil { 
      let loginItems: NSArray = LSSharedFileListCopySnapshot(loginItemsRef, nil).takeRetainedValue() as NSArray 
      println("There are \(loginItems.count) login items") 
      if(loginItems.count > 0) 
      { 
      let lastItemRef: LSSharedFileListItemRef = loginItems.lastObject as LSSharedFileListItemRef 
      for var i = 0; i < loginItems.count; ++i { 
       let currentItemRef: LSSharedFileListItemRef = loginItems.objectAtIndex(i) as LSSharedFileListItemRef 
       if LSSharedFileListItemResolve(currentItemRef, 0, itemUrl, nil) == noErr { 
        if let urlRef: NSURL = itemUrl.memory?.takeRetainedValue() { 
         println("URL Ref: \(urlRef.lastPathComponent)") 
         if urlRef.isEqual(appUrl) { 
          return (currentItemRef, lastItemRef) 
         } 
        } 
       } 
       else { 
        println("Unknown login application") 
       } 
      } 
      //The application was not found in the startup list 
      return (nil, lastItemRef) 
      } 
      else 
      { 
       let addatstart: LSSharedFileListItemRef = kLSSharedFileListItemBeforeFirst.takeRetainedValue() 

       return(nil,addatstart) 
      } 
     } 
    } 
    return (nil, nil) 
} 

Nota appena aggiunto nella if dopo

let loginItems: NSArray = LSSharedFileListCopySnapshot(loginItemsRef, nil).takeRetainedValue() as NSArray 

la funzione era quella di lungo per un commento e ho pensato che questo sarebbe stato più utile di un paio di righe di commento

Nota: anche dovuto modificare il valore di ritorno per gli elenchi vuoti

else 
{ 
    let addatstart: LSSharedFileListItemRef = kLSSharedFileListItemBeforeFirst.takeRetainedValue() 
    return(nil,addatstart) 
} 
+4

Si noti che in OS X 10.10, 'LSSharedFileListItemResolve' è deprecato. Ho dovuto confrontare direttamente 'LSSharedFileListItemCopyResolvedURL (currentItemRef, 0, nil) .takeRetainedValue()' a 'currentItemUrl' per farlo funzionare (dopo aver seguito gli altri suggerimenti di XCode. – JacobEvelyn

+0

@JacobEvelyn Puoi mostrare un esempio esatto?' CurrentItemUrl' non è parte del codice originale e non riesco a capire cosa debba essere effettivamente confrontato – udondan

+2

Sembra che il mio codice fosse 'let currentItemUrl = LSSharedFileListItemCopyResolvedURL (currentItemRef, 0, nil) .takeRetainedValue()' ma credo che questo mi abbia dato errori in alcuni casi La mia soluzione hacky: https://github.com/ComputeForHumanity/compute-for-humanity-app/commit/bd7369d4b07114a7eb7081d37e6a9bf025f5bb3f – JacobEvelyn

Problemi correlati