Swift: how to check group membership between two ODRecord objects?

I have two ODRecord objects in Swift, and am trying to see if one is a member of the other. I tried:

func myIsMember_attempt1(_ r: ODRecord, ofGroup g: ODRecord) -> Bool? {
  do {
    let isM = try g.isMemberRecord(r)
    // -> Constant 'isM' inferred to have type '()', which may be unexpected
   return isM;
  } catch {
    print("Error: \(error)")
    return nil;
  }
}

Despite the discussion of "Return value" at https://developer.apple.com/documentation/opendirectory/odrecord/1427975-ismemberrecord it appears the ODRecord.isMemberRecord() function does not return any value!? [I'm guessing due to the idiosyncratic implementation of the underlying BOOL-returning NSError-taking method on the Objective-C side?]

So noticing there was also a ODRecordContainsMember function available, I tried:

func myIsMember_attempt2(_ r: ODRecord, ofGroup g: ODRecord) -> Bool? {
    let isM = ODRecordContainsMember(
       Unmanaged.passUnretained(g).toOpaque() as! ODRecordRef,
       Unmanaged.passUnretained(r).toOpaque() as! ODRecordRef,
       nil
     )
     // -> Treating a forced downcast to 'ODRecordRef' as optional will never produce 'nil' [??https://bugs.swift.org/browse/SR-4209]
     // -> crashes when run…!
    return isM;
}

so it seems that an ODRecordRef isn't just the raw pointer of an ODRecord?

Is there any chance of the ODRecord.isMemberRecord() method getting fixed in Swift? Is there any way to use ODRecordContainsMember from Swift in the meantime?

I'm guessing due to the idiosyncratic implementation of the underlying BOOL-returning NSError-taking method on the Objective-C side?

Your guess seems to be right. The original method isMemberRecord:error: does not follow the convention of error throwing functions. To import error throwing functions correctly in Swift, the original Objective-C method should return false or nil only when error is thrown.

You should better send a bug report to Apple.


To work this around, you may need to write some Objective-C wrapper, something like this:

ODRecord+hasMember.h

#import <OpenDirectory/OpenDirectory.h>
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface ODRecord (hasMember)
- (NSNumber * _Nullable)hasMember: (ODRecord *)record error: (NSError **)error;
@end

NS_ASSUME_NONNULL_END

ODRecord+hasMember.m

#include "ODRecord+hasMember.h"

@implementation ODRecord (hasMember)

- (NSNumber * _Nullable)hasMember: (ODRecord *)record error: (NSError **)error {
    NSError *resultError = nil;
    BOOL result = [self isMemberRecord:record error:&resultError];
    if( resultError != nil ) {
        if( error != nil ) {
            *error = resultError;
        }
        return nil;
    }
    return [NSNumber numberWithBool:result];
}

@end

{YourProjectName}-Bridging-Header.h

#include "ODRecord+hasMember.h"

And you can use it like this:

func myIsMember_attempt3(_ r: ODRecord, ofGroup g: ODRecord) -> Bool? {
    do {
        let isM = try g.hasMember(r).boolValue
        return isM
    } catch {
        print("Error: \(error)")
        return nil
    }
}
Swift: how to check group membership between two ODRecord objects?
 
 
Q