【问题标题】:How to get Array of Unique PIDs from CGWindowListCopyWindowInfo in Swift如何在 Swift 中从 CGWindowListCopyWindowInfo 获取唯一 PID 数组
【发布时间】:2017-06-21 15:44:42
【问题描述】:

我正在尝试将以下 Objective-C 方法转换为 Swift 3目标是为第 0 层中的所有“屏幕上”窗口元素(桌面元素除外)获取一个唯一进程标识符数组 (kCGWindowOwnerPID)。

我的 Obj-C 方法使用 NSSet 从使用 NSPredicate 过滤的 NSArray 中删除重复的 PID

+ (NSArray*)filteredProcessIndentifiers
{
    pid_t myPid = [[NSProcessInfo processInfo] processIdentifier];

    NSArray *windowList = (id)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly
                                 | kCGWindowListExcludeDesktopElements,
                                   kCGNullWindowID);

    NSArray *uniquePidArray = [[NSSet setWithArray:[
                    [(id)windowList filteredArrayUsingPredicate:
                        [NSPredicate predicateWithFormat:@"(kCGWindowLayer == 0 && kCGWindowOwnerPID != %d)", myPid]]
                    valueForKey:@"kCGWindowOwnerPID"]]
                    allObjects];

    if (windowList) {
        CFRelease(windowList);
    }

    return uniquePidArray;
}

这个 Swift 3 示例用于获取过滤后的元素数组(在第 0 层而不是 myPid),但是这个测试包含 all keys, 和重复的 PID:

/// - returns: Array of WindowInfo dictionaries.
func windowListFiltered() throws -> [AnyObject] {
    var windowListArray: CFArray?
    let options = CGWindowListOption(arrayLiteral: CGWindowListOption.excludeDesktopElements, CGWindowListOption.optionOnScreenOnly)
    let filterPredicate = NSPredicate(format: "(kCGWindowLayer == 0 && kCGWindowOwnerPID != %d)", getpid())

    windowListArray = CGWindowListCopyWindowInfo(options, kCGNullWindowID)
    let filtered = (windowListArray as NSArray?)?.filtered(using: filterPredicate)
    return (filtered as [AnyObject]?)!
}

windowListFiltered() 方法结果产生:

[{
    kCGWindowAlpha = 1;
    kCGWindowBounds =     {
        Height = 436;
        Width = 770;
        X = 525;
        Y = 313;
    };
    kCGWindowIsOnscreen = 1;
    kCGWindowLayer = 0;
    kCGWindowMemoryUsage = 1072;
    kCGWindowName = Debug;
    kCGWindowNumber = 213;
    kCGWindowOwnerName = Finder;
    kCGWindowOwnerPID = 453;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 1;
}, {
    kCGWindowAlpha = 1;
    kCGWindowBounds =     {
        Height = 537;
        Width = 380;
        X = 61;
        Y = 354;
    };
    kCGWindowIsOnscreen = 1;
    kCGWindowLayer = 0;
    kCGWindowMemoryUsage = 1072;
    kCGWindowName = Documents;
    kCGWindowNumber = 3416;
    kCGWindowOwnerName = Finder;
    kCGWindowOwnerPID = 453;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 1;
}, {
    kCGWindowAlpha = 1;
    kCGWindowBounds =     {
        Height = 22;
        Width = 1414;
        X = 118;
        Y = 28;
    };
    kCGWindowIsOnscreen = 1;
    kCGWindowLayer = 0;
    kCGWindowMemoryUsage = 128208;
    kCGWindowName = "swift3 - Cannot subscript a value of type [[String:Any]] with an index of type 'String' - Swift 3 - Stack Overflow";
    kCGWindowNumber = 7798;
    kCGWindowOwnerName = WindowMizer;
    kCGWindowOwnerPID = 495;
    kCGWindowSharingState = 1;
    kCGWindowStoreType = 2;
}]

我需要的是一个像这样的数组:

[453,495]

我已经能够部分到达那里,但我无法从filtered 数组中提取一组 PID。此尝试迭代一个数组以构建第二个数组,这确实有效,但仍然存在重复的 PID - 我可以消除它,但我正在尝试找到实现原始 Goal 的最佳方法。

func filteredProcessIndentifiers() throws -> [Int] {
    var processIds:[Int] = []
    var windowListArray: CFArray?
    let options = CGWindowListOption(arrayLiteral: CGWindowListOption.excludeDesktopElements, CGWindowListOption.optionOnScreenOnly)
    let filterPredicate = NSPredicate(format: "(kCGWindowLayer == 0 && kCGWindowOwnerPID != %d)", getpid())
    windowListArray = CGWindowListCopyWindowInfo(options, kCGNullWindowID)
    let filtered = (windowListArray as NSArray?)?.filtered(using: filterPredicate) as? [[ String : Any]]

    for dict in filtered! {
        processIds.append((dict["kCGWindowOwnerPID"] as! Int))
    }

    return processIds
}

简单来说,考虑到我有filtered 数组,我尝试返回:

filtered["kCGWindowOwnerPID"]

由于错误而无法编译:“Type 'NSArray?'没有下标成员”

我希望创建一些更简洁的东西,比如漂亮的 Objective-C 示例 :-)。今晚我会再试一次,并专注于使用相当于NSSet 的 Swift3 来消除重复。

任何有关从CGWindowListCopyWindowInfo() 获取唯一进程标识符数组的最佳方法的见解将不胜感激。

【问题讨论】:

    标签: objective-c arrays swift3 nspredicate core-foundation


    【解决方案1】:

    函数filteredProcessIndentifiers里面的for循环改成这样:

    for diction in filtered! {
        let test = diction as? Dictionary<String,Any>
        if let item = test{
             print("testa: \(String(describing: item["kCGWindowOwnerPID"]))")
        }
    }
    

    谢谢。我已经试图解决这个问题将近两天了,遇到你的问题给了我这个想法,它奏效了!所以谢谢你。

    【讨论】:

      猜你喜欢
      • 2015-10-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      • 2023-01-28
      • 1970-01-01
      相关资源
      最近更新 更多