在过去的几周里,我一直在swift编写一个mac应用程序,既可以进入mac编程,也可以在我的工作场所迁移到它时快速练习。我目前正在尝试通过定制BDungan's blog上提供的代码来获取一些代码,将我的应用程序添加为“启动时启动”应用程序
到目前为止,经过几个小时的捣乱,我想出了以下内容:
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)
}
}
然而,我遇到了两个问题。
问题1
Swift不希望我将NSURL与CFURLRef进行比较......现在我只是为了让应用程序运行而使用了Xcode建议,但我100%肯定它没有做我认为的那样。 (参见//问题1)。
在objective-c中,NSURL和CFURLRef(或CFURL)之间似乎允许免费桥接,但是在尝试施放时,条件转换或任何种类的swift作为(在此处插入正确的字符)接近我的代码不可避免地不会建立。我收到的错误如下:
Unmanaged不是NSURL的子类型:
if appURL as Unmanaged<CFURLRef> == itemURL
e.t.c。
问题2
虽然这段代码目前没有发出任何警告或错误......但在尝试编译时,我得到一个Command failed due to signal: Segmentation fault: 11
,坦率地说......超出了我的范围。
答案 0 :(得分:12)
我设法根据Brian Dunagan的Objective C方法获得了这个构建的工作实现。 我也遇到了你的编译器seg故障问题,但这是由于尝试转换为无效类型引起的;获得正确的类型可以解决问题。
我无法让kLSSharedFileListItemLast
正确返回最后一个文件项引用,因为它总是会导致seg错误。为了解决这个问题,我修改了itemReferencesInLoginItems
函数以返回一个项目引用元组。
元组中的第一项是现有的应用程序引用(如果存在),第二项是列表的最后一个引用。使用这种方法,我们可以避免依赖kLSSharedFileListItemLast
。
这是代码,随意使用它!我很想知道是否有办法让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 :(得分:5)
令人惊讶的答案,但你忘记了一个if语句来检查如果没有项目存在就防止错误解开空值
这是一个功能的快速解决方案,希望它可以帮助某人
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)
}
注意只是在
之后的if语句中添加let loginItems: NSArray = LSSharedFileListCopySnapshot(loginItemsRef, nil).takeRetainedValue() as NSArray
该功能是为了评论,我认为这比评论的几行更有帮助
注意:还必须更改空列表的返回值
else
{
let addatstart: LSSharedFileListItemRef = kLSSharedFileListItemBeforeFirst.takeRetainedValue()
return(nil,addatstart)
}