Using Cfarraygetvalueatindex in Swift with Unsafepointer (Aupreset)

Using CFArrayGetValueAtIndex in Swift with UnsafePointer (AUPreset)

Have you tried this?:

    let aPreset = UnsafePointer<AUPreset>(CFArrayGetValueAtIndex(mEQPresetsArray, indexPath.row))

CTFramesetterSuggestFrameSizeWithConstraints sometimes returns incorrect size?

CTFramesetterSuggestFrameSizeWithConstraints works correctly. The reason that you get a height that is too short is because of the leading in the default paragraph style attached to attributed strings. If you don't attach a paragraph style to the string then CoreText returns the height needed to render the text, but with no space between the lines. This took me forever to figure out. Nothing in the documentation spells it out. I just happened to notice that my heights were short by an amount equal to (number of lines x expected leading). To get the height result you expect you can use code like the following:

NSString  *text = @"This\nis\nsome\nmulti-line\nsample\ntext."
UIFont *uiFont = [UIFont fontWithName:@"Helvetica" size:17.0];
CTFontRef ctFont = CTFontCreateWithName((CFStringRef) uiFont.fontName, uiFont.pointSize, NULL);

// When you create an attributed string the default paragraph style has a leading
// of 0.0. Create a paragraph style that will set the line adjustment equal to
// the leading value of the font.
CGFloat leading = uiFont.lineHeight - uiFont.ascender + uiFont.descender;
CTParagraphStyleSetting paragraphSettings[1] = { kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &leading };

CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(paragraphSettings, 1);
CFRange textRange = CFRangeMake(0, text.length);

// Create an empty mutable string big enough to hold our test
CFMutableAttributedStringRef string = CFAttributedStringCreateMutable(kCFAllocatorDefault, text.length);

// Inject our text into it
CFAttributedStringReplaceString(string, CFRangeMake(0, 0), (CFStringRef) text);

// Apply our font and line spacing attributes over the span
CFAttributedStringSetAttribute(string, textRange, kCTFontAttributeName, ctFont);
CFAttributedStringSetAttribute(string, textRange, kCTParagraphStyleAttributeName, paragraphStyle);

CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(string);
CFRange fitRange;

CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, textRange, NULL, bounds, &fitRange);

CFRelease(framesetter);
CFRelease(string);

Error with fetching value from CFArray

You cannot force cast an UnsafePointer<Void> to a type. You must first convert that void pointer to UnsafePointer<Type> then take its memory:

let aPerson = UnsafePointer<ABRecordRef>(CFArrayGetValueAtIndex(allPeople, i)).memory

FYI... ABAddressBook has been deprecated on iOS 9. For new code targeting that OS, use CNContactStore instead.

How to convert CFArray to Swift Array?

Here is how to do this, based on the current state of the Swift compiler and Swift documentation. Hopefully this gets cleaned up in later betas.

UPDATE: Since Beta 5, reinterpretCast has been renamed to unsafeBitCast, and a CTLine object must be sent to it as an input. Way #2 still does not work.


Way #1 - Use the CFArray directly

let line: CTLine = reinterpretCast(CFArrayGetValueAtIndex(lines, 0))

Regarding Gary Makin's comments - The Ref can be dropped from CTLineRef, but this does not change ARC vs non-ARC. According to Using Swift with Cocoa and Objective-C pages 53-54, ref and non-ref are identical to the compiler. Attempting to call CFRelease causes a compiler error.


Way #2 - Convert the CFArray to a Swift array - Does not currently work

Ideally, we want to convert lines to a Swift array of CTLine objects since we know that's what is returned by CTFrameGetLines, giving us type safety after the conversion. Probably due to a compiler bug, the array can be converted to an [AnyObject] array, but not to [CTLine]. According to Apple's documentation, this should work:

let linesNS: NSArray  = CTFrameGetLines(frame)
let linesAO: [AnyObject] = linesNS as [AnyObject]
let lines: [CTLine] = linesAO as [CTLine]

This converts CFArray to NSArray, then NSArray to Swift Array [AnyObject], then downcasts that array to the specific type CTLine. This compiles, but when it is run, there is an EXC_BREAKPOINT crash on the last line.

How to use UnsafeMutablePointerOpaquePointer in Swift?

PMPrinter and PMPaper are defined in the PrintCore framework
as pointer to an "incomplete type"

typedef struct OpaquePMPrinter*         PMPrinter;
typedef struct OpaquePMPaper* PMPaper;

Those are imported into Swift as OpaquePointer, and are a bit
cumbersome to use.

The second argument to PMSessionGetCurrentPrinter() is a pointer to
a non-optional PMPrinter variable, and in Swift it must be
initialized before being passed as an inout argument. One possible way
to initialize a null-pointer is to use unsafeBitCast.

The easiest way to get the PMPaper objects from the array seems to
be to use CFArrayGetValueAtIndex() instead of bridging it to a
Swift array. That returns a UnsafeRawPointer which can be converted
to an OpaquePointer.

This worked in my test:

let printInfo = NSPrintInfo.shared()
let printSession = PMPrintSession(printInfo.pmPrintSession())

var currentPrinter = unsafeBitCast(0, to: PMPrinter.self)
PMSessionGetCurrentPrinter(printSession, ¤tPrinter);

var paperListUnmanaged: Unmanaged<CFArray>?
PMPrinterGetPaperList(currentPrinter, &paperListUnmanaged)
guard let paperList = paperListUnmanaged?.takeUnretainedValue() else {
fatalError()
}
for idx in 0..<CFArrayGetCount(paperList) {
let paper = PMPaper(CFArrayGetValueAtIndex(paperList, idx))!
var width = 0.0, height = 0.0
PMPaperGetWidth(paper, &width)
PMPaperGetHeight(paper, &height)
print(width, height)
}

Displaying SSID in iOS App using Swift

I figured out that it would be much easier to create a bridge from Swift to Objective-C.

Importing framework:

#import <SystemConfiguration/CaptiveNetwork.h>

Code to get the SSID of user's connected WiFi:

func getMAC()->(success:Bool,ssid:String,mac:String){

if let cfa: NSArray = CNCopySupportedInterfaces() {
for x in cfa {
if let dict = CFBridgingRetain(CNCopyCurrentNetworkInfo(x as! CFString)) {
let ssid = dict ["SSID"]!
let mac = dict["BSSID"]!
return (true, ssid as! String, mac as! String)
}
}
}
return (false,"","")
}

Print and display in a label when needed:

let x = getMAC()
if x.success {
MAClabel = x.mac
SSIDlabel = x.ssid
print(x.mac)
print (x.ssid)
}

I hope that those with this question would find this useful!

Swift: CFArray : get values as UTF Strings

There are some issues here. First, TISCreateInputSourceList()
has "Create" in its name which means that it returns a (+1) retained
object and you have to take the value with takeRetainedValue(),
not takeUnretainedValue(), otherwise the code will leak memory:

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue()

You could now use the CFArray... methods to get values from the array,
but it is much easier to convert it to a NSArray (which is "toll-free bridged"):

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue() as NSArray

This is not an array of CFStringRef values but an array of
TISInputSource objects. You can convert the NSArray to a Swift array:

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue()
as NSArray as! [TISInputSource]

The forced cast as! is acceptable here because the function is
documented to return an array of input sources.

Now you can simply iterate over the elements of the array:

for src in srcs  {
// do something with `src` (which is a `TISInputSource`)
}

The properties of an input source are retrieved with the TISGetInputSourceProperty() function, for example:

let ptr = TISGetInputSourceProperty(src, kTISPropertyInputSourceID)

This returns a "void pointer" (UnsafeMutablePointer<Void>) which has to be converted to an object
pointer of the appropriate type (which is CFStringRef for the
kTISPropertyInputSourceID property). Unfortunately, this is a bit
complicated (compare How to cast self to UnsafeMutablePointer<Void> type in swift):

let val = Unmanaged<CFString>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()

Again we can take advantage of toll-free bridging, now from
CFStringRef to NSString and String:

let val = Unmanaged<CFString>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()
as String

Putting it all together:

let srcs = TISCreateInputSourceList(nil, true).takeRetainedValue()
as NSArray as! [TISInputSource]
for src in srcs {
let ptr = TISGetInputSourceProperty(src, kTISPropertyInputSourceID)
let val = Unmanaged<CFString>.fromOpaque(COpaquePointer(ptr)).takeUnretainedValue()
as String
print(val)
}

How to convert Swift array into CFArray?

You can initialize your UnsafeMutablePointer with your array so long as you set your CGWindowIDs to CFTypeRef:

var windows: [CFTypeRef] = [1, 2]
var windowsPointer = UnsafeMutablePointer<UnsafePointer<Void>>(windows)
var cfArray = CFArrayCreate(nil, windowsPointer, windows.count, nil)


Related Topics



Leave a reply



Submit