0

My code:

//search all of applications
let queryString = "kMDItemContentTypeTree=com.apple.application"

// sort by last metadata change
let sorting = [kMDItemAttributeChangeDate] as CFArray

// create query and assign sorting param
let query = MDQueryCreate(kCFAllocatorDefault, queryString as CFString, nil, sorting)
        
// ISSUE HERE
// Set comparation block that called for sorting
MDQuerySetSortComparatorBlock(query, {
            if let date1 = $0 as? Date,
               let date2 = $1 as? Date {
                  return date1 < date2 ? .compareLessThan : .compareGreaterThan
              }
            
            return CFComparisonResult.compareEqualTo
        })


MDQuerySetDispatchQueue(query, DispatchQueue(label: "background", qos: .background) )
MDQueryExecute(query, CFOptionFlags())
        

issue is in correct way to write MDQuerySetSortComparatorBlock - I'm do not understand how is it must be written

I see warnings:

Cast from 'UnsafePointer<Unmanaged?>?' (aka 'Optional<UnsafePointer<Optional<Unmanaged>>>') to unrelated type 'Date' always fails

Andrew_STOP_RU_WAR_IN_UA
  • 9,318
  • 5
  • 65
  • 101
  • `Unmanaged` is always such fun. I think you have to call either `.takeRetainedValue()` or `.takeUnretainedValue()`. I'm guessing the former. So I think it would be `if let date1 = $0?.pointee?.takeRetainedValue() as? Date` – Chip Jarred Oct 13 '22 at 04:17
  • 1
    @ChipJarred thanks, it works! post it as an answer) – Andrew_STOP_RU_WAR_IN_UA Oct 13 '22 at 04:26
  • I'll do that. I'm glad my guess, albeit a hazily informed one, was right (or at least worked). – Chip Jarred Oct 13 '22 at 04:41
  • 1
    BTW - I just noticed and fixed what I think is a bug in the comparison closure. Namely, after it acquires both dates, if `date1 < date2` it returned `.compareLessThan`, otherwise `.compareGreaterThan`. The only time it would return `.compareEqualTo` is when one or both of casts to `Date` fails. That's clearly not right. So it wouldn't compare equal dates as equal. You probably should consider what the RightThing is for your app when the casts fail. I updated my answer to fix the comparison, and to use trailing closure syntax. – Chip Jarred Oct 15 '22 at 23:03
  • Assuming `fatalError` is not an option for non-dates, one way is do the comparison such that `nil` is greater than non-nil values. That will collect the invalid `Date` elements at the end, where it's easy and efficient to remove them after the sort. – Chip Jarred Oct 15 '22 at 23:22

1 Answers1

1

I always have to spend time looking up what the deal is with Unmanaged because I need it so infrequently. Apparently my guess at it in comments based on hazy memory of the last time I encountered Unmanaged worked for OP, so I'm putting it here. Basically it comes down to both dereferencing the pointer using its .pointee property then calling .takeRetainedValue() on that, with appropriate optional unwrapping in between.

MDQuerySetSortComparatorBlock(query)
{
    guard let date1 = $0?.pointee?.takeRetainedValue() as? Date,
          let date2 = $1?.pointee?.takeRetainedValue() as? Date
    else
    {
        // Do you really want to treat non-dates as equal?
        return .compareEqualTo
    }
    
    if date1 < date2 { return .compareLessThan }
    return date1 == date2 ? .compareEqualTo : .compareGreaterThan
}

Exactly what to do with the possibility of the casts to Date resulting in nil depends on your app, but one possibility is do the comparison so that all the ones where the cast to Date fails, or where the pointer is genuinely nil, collect at the end.

MDQuerySetSortComparatorBlock(query)
{
    guard let date1 = $0?.pointee?.takeRetainedValue() as? Date else {
        return .compareGreaterThan
    }
    guard let date2 = $1?.pointee?.takeRetainedValue() as? Date else {
        return .compareLessThan
    }
    
    if date1 < date2 { return .compareLessThan }
    return date1 == date2 ? .compareEqualTo : .compareGreaterThan
}

Then when you get the query results, you can make a reverse pass to remove elements with invalid dates without needing to shift elements.

Chip Jarred
  • 2,600
  • 7
  • 12