2014-10-20 12 views
15

W ciągu ostatnich kilku tygodni pisałem szybko aplikację Mac, zarówno do programowania w języku mac, jak i do szybkiego przeszukiwania, kiedy przenosimy się do niego w moim miejscu pracy. Obecnie próbuję uzyskać kod działający, aby dodać moją aplikację jako aplikację "Uruchom na starcie", dostosowując kod dostarczony pod adresem BDungan's blogSwift - uruchomienie aplikacji Mac do uruchomienia przy uruchomieniu

Do tej pory, po wielu godzinach, natknąłem się na następujące kwestie:

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) 
    } 
} 

Występują jednak dwa problemy.

Problem 1

Swift nie chce mnie do porównywania bibliotece NSURL do CFURLRef ... teraz poszłam z sugestią Xcode tak aby uzyskać działających aplikacji, ale jestem 100% pewien, że nie robi tego, co myślę, że jest. (patrz // PROBLEM 1).

Wygląda na to, że między NSURL a CFURLRef (lub CFURL) było dozwolone bezpłatne łączenie, jednak przy próbie rzutowania, warunkowej obsady lub dowolnej odmiany szybkiej, jak (Wstaw poprawną postać tutaj) podejście do mojego kodu nieuchronnie nie byłoby " t budować. I pojawiają się błędy takie jak:

niezarządzalny nie jest podtypem bibliotece NSURL: if appURL as Unmanaged<CFURLRef> == itemURL

itd.

Problem 2

Chociaż ten kod aktualnie nie daje ostrzeżenia lub błędy ... podczas próby kompilacji dostaję Command failed due to signal: Segmentation fault: 11, który szczerze mówiąc ... jest poza mną.

Odpowiedz

11

Udało mi się uzyskać działającą implementację tego zbudowanego w oparciu o podejście Celu C Briana Dunagana. Wystąpił również problem z uszkodzeniem kompu, ale było to spowodowane próbą rzutowania na nieprawidłowe typy; uzyskanie odpowiednich typów rozwiązuje problem.

Nie można uzyskać kLSSharedFileListItemLast, aby poprawnie zwrócić ostatnią referencję do pliku, ponieważ zawsze powodowałoby błąd w seg. Aby obejść ten problem, zmodyfikowałem funkcję itemReferencesInLoginItems, aby zwrócić krotkę odniesień do elementów.

Pierwszą pozycją w krotce jest istniejąca referencja do aplikacji, jeśli istnieje, druga pozycja jest ostatnią referencją na liście. Dzięki takiemu podejściu możemy uniknąć konieczności polegania na kLSSharedFileListItemLast.

Oto kod, nie krępuj się go używać! Chciałbym wiedzieć, czy istnieje sposób, aby zadziałał 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

Co po piaskownicy Włączone ? – ak2g

4

niesamowite odpowiedź ale zapomniałeś if sprawdzić uniknięcia błędu odwijania pustą wartość, jeśli nie istnieją żadne elementy

Oto szybkie rozwiązanie dla jednej funkcji, mam nadzieję, że ktoś pomoże

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) 
} 

Uwaga prostu dodane w if po

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

funkcja była długa na komentarz i myślałem, że to będzie bardziej pomocny niż kilka linijek komentarza

Uwaga: Również zmiany wartości zwracanej dla pustych list

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

Należy zauważyć, że w OS X 10.10 'LSSharedFileListItemResolve' jest przestarzałe. Musiałem bezpośrednio porównać 'LSSharedFileListItemCopyResolvedURL (currentItemRef, 0, zero) .takeRetainedValue()' z 'currentItemUrl', aby to działało (po zastosowaniu się do innych sugestii XCode) – JacobEvelyn

+0

@JacobEvelyn Czy mógłbyś pokazać dokładny przykład?' CurrentItemUrl' nie jest częścią oryginalnego kodu i nie wiem, co faktycznie musi być porównane – udondan

+2

Wygląda na to, że mój kod był 'let currentItemUrl = LSSharedFileListItemCopyResolvedURL (currentItemRef, 0, zero) .takeRetainedValue()' ale uważam, że to dało mi błędy w niektórych przypadkach Moje hacky obejść: https://github.com/ComputeForHumanity/compute-for-humanity-app/commit/bd7369d4b07114a7eb7081d37e6a9bf025f5bb3f – JacobEvelyn

Powiązane problemy