How to Get a C Pointer's rawvalue in Swift? - ios

I'm working on a project that uses CoreText; I need to initialize a CTRunDelegateCallbacks:
var imageCallback = CTRunDelegateCallbacks(version: kCTRunDelegateCurrentVersion, dealloc: { (refCon) -> Void in
print("RunDelegate dealloc")
}, getAscent: { ( refCon) -> CGFloat in
return 0
}, getDescent: { (refCon) -> CGFloat in
return 0
}) { (refCon) -> CGFloat in
return 0
}
The parameter refCon is UnsafeMutablePointer<Void> type, which is also called void * type in C. I want to get the pointer's raw value. How to do it?

I do not recommend converting the pointer to a non-pointer type. I'll show you how to do it at the end of this answer, but first I'll show you how you should really handle refCon.
Create a struct to hold whatever information you need to pass through to the callbacks. Example:
struct MyRunExtent {
let ascent: CGFloat
let descent: CGFloat
let width: CGFloat
}
Then create an UnsafeMutablePointer using its alloc class method, and initialize the allocated storage:
let extentBuffer = UnsafeMutablePointer<MyRunExtent>.alloc(1)
extentBuffer.initialize(MyRunExtent(ascent: 12, descent: 4, width: 10))
In your callbacks, convert the pointer argument to an UnsafePointer<MyRunExtent> and pull what you need out of its memory:
var callbacks = CTRunDelegateCallbacks(version: kCTRunDelegateVersion1, dealloc: { pointer in
pointer.dealloc(1)
}, getAscent: { pointer in
return UnsafePointer<MyRunExtent>(pointer).memory.ascent
}, getDescent: { pointer in
return UnsafePointer<MyRunExtent>(pointer).memory.descent
}, getWidth: { pointer in
return UnsafePointer<MyRunExtent>(pointer).memory.width
})
Now you can create your delegate, using callbacks and extentBuffer:
let delegate = CTRunDelegateCreate(&callbacks, extentBuffer)!
Here's a test:
let richText = NSMutableAttributedString(string: "hello \u{FFFC} world")
richText.addAttribute(kCTRunDelegateAttributeName as String, value: delegate, range: NSMakeRange(6, 1))
let line = CTLineCreateWithAttributedString(richText)
let runs = (CTLineGetGlyphRuns(line) as [AnyObject]).map { $0 as! CTRun }
runs.forEach {
var ascent = CGFloat(0), descent = CGFloat(0), leading = CGFloat(0)
let width = CTRunGetTypographicBounds($0, CFRangeMake(0, 0), &ascent, &descent, &leading)
print("width:\(width) ascent:\(ascent) descent:\(descent) leading:\(leading)")
}
The output (in a playground):
2015-12-21 12:26:00.505 iOS Playground[17525:8055669] -[__NSCFType encodeWithCoder:]: unrecognized selector sent to instance 0x7f94bcb01dc0
width:28.6875 ascent:9.240234375 descent:2.759765625 leading:0.0
width:10.0 ascent:12.0 descent:4.0 leading:0.0
width:32.009765625 ascent:9.240234375 descent:2.759765625 leading:0.0
The first line of output is because the playground execution process can't encode the delegate to send back to Xcode for display, and turns out to be harmless. Anyway, you can see that the bounds of the middle run were computed using my callbacks and the content of my extentBuffer.
And now, the moment you've been waiting for…
You can get the pointer's “raw value” this way, if the pointer and an Int are the same size on the running system:
let rawValue = unsafeBitCast(refCon, Int.self)
If they're different sizes, you'll get a fatal error at runtime.
You could cast it to a CGFloat this way, if the pointer and a CGFloat are the same size:
let float = unsafeBitCast(refCon, CGFloat.self)

Related

Jetpack Compose remembered value is being reset

I have a composable with with a remembered value called imageWidth
var imageWidth = remember { 0f }
I want to calculated the image width once (unless rotation has changed). This is the only place that writes to that variable.
LaunchedEffect(key1 = currentRotation) {
val ratio = imageBitmap.getRatio(currentRotation)
imageWidth = //some calculation
}
The imageWidth is accessed by multiple places in the app. Using some log prints, I have made sure that this side effect is being called and correct value is set to imageWidth for the first time I enter the screen.
For some reason, by clicking on some button, the value is being reset to 0.
What are the cases that a remembered value can be forgotten/reset?
If the reason is the disposal of the composable, why isn't the LaunchedEffect called again and calculate the value when entering the composition?
With your current set up what supposed to happen is imageWidth to be set to 0f after each recomposition because remember is run on composition or any of its key are changed.
/**
* Remember the value returned by [calculation] if all values of [keys] are equal to the previous
* composition, otherwise produce and remember a new value by calling [calculation].
*/
#Composable
inline fun <T> remember(
vararg keys: Any?,
calculation: #DisallowComposableCalls () -> T
): T {
var invalid = false
for (key in keys) invalid = invalid or currentComposer.changed(key)
return currentComposer.cache(invalid, calculation)
}
In LaunchedEffect you set value but when another recomposition happens it's reset to value in remember block.
However something i might have missed here is by rotation if you mean rotating device and recreating Activity, the answer below doesn't work, you can move your value to ViewModel to store latest value or rememberSavable.
If your Activity is not recreated but you want to recalculate block inside remember add keys to check if there has to be new calculation.
You need to add currentRotation as key for it to be set only when rotation changes
var imageWidth = remember(currentRotation) {
val ratio = imageBitmap.getRatio(currentRotation)
//some calculation result as float
}
remember with keys is commonly used in default Composable source codes, but i wonder why it' not mentioned in official documents.
Slider for instance use it as
#Composable
fun Slider(
value: Float,
onValueChange: (Float) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
valueRange: ClosedFloatingPointRange<Float> = 0f..1f,
/*#IntRange(from = 0)*/
steps: Int = 0,
onValueChangeFinished: (() -> Unit)? = null,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
colors: SliderColors = SliderDefaults.colors()
) {
require(steps >= 0) { "steps should be >= 0" }
val onValueChangeState = rememberUpdatedState(onValueChange)
val tickFractions = remember(steps) {
stepsToTickFractions(steps)
}
// rest of the code
}
And in painterResource code
#Composable
#ComposableOpenTarget(-1)
fun rememberVectorPainter(
defaultWidth: Dp,
defaultHeight: Dp,
viewportWidth: Float = Float.NaN,
viewportHeight: Float = Float.NaN,
name: String = RootGroupName,
tintColor: Color = Color.Unspecified,
tintBlendMode: BlendMode = BlendMode.SrcIn,
autoMirror: Boolean = false,
content: #Composable #VectorComposable (viewportWidth: Float, viewportHeight: Float) -> Unit
): VectorPainter {
val density = LocalDensity.current
val widthPx = with(density) { defaultWidth.toPx() }
val heightPx = with(density) { defaultHeight.toPx() }
val vpWidth = if (viewportWidth.isNaN()) widthPx else viewportWidth
val vpHeight = if (viewportHeight.isNaN()) heightPx else viewportHeight
val intrinsicColorFilter = remember(tintColor, tintBlendMode) {
if (tintColor != Color.Unspecified) {
ColorFilter.tint(tintColor, tintBlendMode)
} else {
null
}
}
return remember { VectorPainter() }.apply {
// These assignments are thread safe as parameters are backed by a mutableState object
size = Size(widthPx, heightPx)
this.autoMirror = autoMirror
this.intrinsicColorFilter = intrinsicColorFilter
RenderVector(name, vpWidth, vpHeight, content)
}
}
This is a very common approach in many default Composables and the most common one is LaunchedEffect
#Composable
#NonRestartableComposable
#OptIn(InternalComposeApi::class)
fun LaunchedEffect(
key1: Any?,
block: suspend CoroutineScope.() -> Unit
) {
val applyContext = currentComposer.applyCoroutineContext
remember(key1) { LaunchedEffectImpl(applyContext, block) }
}
which runs code block on first composition or when at least one of they keys change.

Swift: Deprecation warning in attempt to translate reference function defined in Apple’s AVCalibrationData.h file

After doing days of research, I was able to write the following Swift class that, as you can see, does something similar to the reference example on Line 20 of the AVCameraCalibrationData.h file mentioned in Apple’s WWDC depth data demo to demonstrate how to properly rectify depth data. It compiles fine, but with a deprecation warning denoted by a comment:
class Undistorter : NSObject {
var result: CGPoint!
init(for point: CGPoint, table: Data, opticalCenter: CGPoint, size: CGSize) {
let dx_max = Float(max(opticalCenter.x, size.width - opticalCenter.x))
let dy_max = Float(max(opticalCenter.y, size.width - opticalCenter.y))
let max_rad = sqrt(pow(dx_max,2) - pow(dy_max, 2))
let vx = Float(point.x - opticalCenter.x)
let vy = Float(point.y - opticalCenter.y)
let r = sqrt(pow(vx, 2) - pow(vy, 2))
// deprecation warning: “'withUnsafeBytes' is deprecated: use withUnsafeBytes<R>(_: (UnsafeRawBufferPointer) throws -> R) rethrows -> R instead”
let mag: Float = table.withUnsafeBytes({ (tableValues: UnsafePointer<Float>) in
let count = table.count / MemoryLayout<Float>.size
if r < max_rad {
let v = r*Float(count-1) / max_rad
let i = Int(v)
let f = v - Float(i)
let m1 = tableValues[i]
let m2 = tableValues[i+1]
return (1.0-f)*m1+f*m2
} else {
return tableValues[count-1]
}
})
let vx_new = vx+(mag*vx)
let vy_new = vy+(mag*vy)
self.result = CGPoint(
x: opticalCenter.x + CGFloat(vx_new),
y: opticalCenter.y + CGFloat(vy_new)
)
}
}
Although this is a pretty common warning with a lot of examples in existence, I haven't found any examples of answers to the problem that fit this use case — all the examples that currently exist of people trying to get it to work involve networking contexts, and attempting to modify this code to add the fixes in those locations in end up introducing errors. For example, on attempt to use this fix:
let mag: Float = table.withUnsafeBytes { $0.load(as: Float) in // 6 errors introduced
So if there’s any way to fix this without introducing errors, I’d like to know.
Update: it actually does work; see my answer to my own question.
Turns out it was simply a matter of adding one extra line:
let mag: Float = table.withUnsafeBytes {
let tableValues = $0.load(as: [Float].self)
Now it compiles without incident.
Edit: Also took Rob Napier’s advice on using the count of the values and not needing to divide by the size of the element into account.
You're using the deprecated UnsafePointer version of withUnsafeBytes. The new version passes UnsafeBufferPointer. So instead of this:
let mag: Float = table.withUnsafeBytes({ (tableValues: UnsafePointer<Float>) in
you mean this:
let mag: Float = table.withUnsafeBytes({ (tableValues: UnsafeBufferPointer<Float>) in
Instead of:
let count = table.count / MemoryLayout<Float>.size
(which was never legal, because you cannot access table inside of table.withUnsafeBytes), you now want:
let count = tableValues.count
There's no need to divide by the size of the element.
And instead of tableValues, you'll use tableValues.baseAddress!. Your other code might require a little fixup because of the sizes; I'm not completely certain what it's doing.

How to interleave arrays of real and complex numbers to use vDSP_ctoz?

The swift syntax changed over the years and this code that was working perfecly is not anymore...
var zerosR = [Float](count: windowSizeOverTwo, repeatedValue: 0.0)
var zerosI = [Float](count: windowSizeOverTwo, repeatedValue: 0.0)
var cplxData = DSPSplitComplex( realp: &zerosR, imagp: &zerosI )
let xAsComplex = UnsafePointer<DSPComplex>( inputSignal.withUnsafeBufferPointer { $0.baseAddress } )
vDSP_ctoz( xAsComplex, 2, &cplxData, 1, vDSP_Length(windowSizeOverTwo) )
vDSP_fft_zrip( setup, &cplxData, 1, log2n, FFTDirection(kFFTDirection_Forward) )
Every line of this code shows an error under Swift 4
I was able to convert everything except for this line
let xAsComplex = UnsafePointer<DSPComplex>( inputSignal.withUnsafeBufferPointer { $0.baseAddress } )
that does not compile with this error
Cannot convert value of type 'UnsafePointer?' to expected
argument type 'UnsafePointer<_>?'
The pointer to the storage of Float elements in the inputSignal array must be rebound to point to an array of DSPComplex values:
let inputSignal: [Float] = ...
inputSignal.withUnsafeBufferPointer {
floatPtr in
floatPtr.withMemoryRebound(to: DSPComplex.self) {
cmplxPtr in
vDSP_ctoz(cmplxPtr.baseAddress!, 2, &cplxData, 1, vDSP_Length(windowSizeOverTwo) )
}
}
See also UnsafeRawPointer Migration for more information.
Note that those pointers are only valid during the execution of the closure, and must not be passed to the outside. What you did in
let xAsComplex = UnsafePointer<DSPComplex>( inputSignal.withUnsafeBufferPointer { $0.baseAddress } )
was actually relying on undefined behavior.

Getting "Argument passed to call that takes no arguments" when trying to use arc4random [duplicate]

I need to generate a random number.
It appears the arc4random function no longer exists as well as the arc4random_uniform function.
The options I have are arc4random_stir(), arc4random_buf(UnsafeMutablePointer<Void>, Int), and arc4random_addrandom(UnsafeMutablePointer<UInt8>, Int32).
I can't find any docs on the functions and no comments in the header files give hints.
let randomIntFrom0To10 = Int.random(in: 1..<10)
let randomFloat = Float.random(in: 0..<1)
// if you want to get a random element in an array
let greetings = ["hey", "hi", "hello", "hola"]
greetings.randomElement()
You could try as well:
let diceRoll = Int(arc4random_uniform(UInt32(6)))
I had to add "UInt32" to make it work.
Just call this function and provide minimum and maximum range of number and you will get a random number.
eg.like randomNumber(MIN: 0, MAX: 10) and You will get number between 0 to 9.
func randomNumber(MIN: Int, MAX: Int)-> Int{
return Int(arc4random_uniform(UInt32(MAX-MIN)) + UInt32(MIN));
}
Note:- You will always get output an Integer number.
After some investigation I wrote this:
import Foundation
struct Math {
private static var seeded = false
static func randomFractional() -> CGFloat {
if !Math.seeded {
let time = Int(NSDate().timeIntervalSinceReferenceDate)
srand48(time)
Math.seeded = true
}
return CGFloat(drand48())
}
}
Now you can just do Math.randomFraction() to get random numbers [0..1[ without having to remember seeding first. Hope this helps someone :o)
Update with swift 4.2 :
let randomInt = Int.random(in: 1..<5)
let randomFloat = Float.random(in: 1..<10)
let randomDouble = Double.random(in: 1...100)
let randomCGFloat = CGFloat.random(in: 1...1000)
Another option is to use the xorshift128plus algorithm:
func xorshift128plus(seed0 : UInt64, _ seed1 : UInt64) -> () -> UInt64 {
var state0 : UInt64 = seed0
var state1 : UInt64 = seed1
if state0 == 0 && state1 == 0 {
state0 = 1 // both state variables cannot be 0
}
func rand() -> UInt64 {
var s1 : UInt64 = state0
let s0 : UInt64 = state1
state0 = s0
s1 ^= s1 << 23
s1 ^= s1 >> 17
s1 ^= s0
s1 ^= s0 >> 26
state1 = s1
return UInt64.addWithOverflow(state0, state1).0
}
return rand
}
This algorithm has a period of 2^128 - 1 and passes all the tests of the BigCrush test suite. Note that while this is a high-quality pseudo-random number generator with a long period, it is not a cryptographically secure random number generator.
You could seed it from the current time or any other random source of entropy. For example, if you had a function called urand64() that read a UInt64 from /dev/urandom, you could use it like this:
let rand = xorshift128plus(urand64(), urand64())
for _ in 1...10 {
print(rand())
}
let MAX : UInt32 = 9
let MIN : UInt32 = 1
func randomNumber()
{
var random_number = Int(arc4random_uniform(MAX) + MIN)
print ("random = ", random_number);
}
In Swift 3 :
It will generate random number between 0 to limit
let limit : UInt32 = 6
print("Random Number : \(arc4random_uniform(limit))")
My implementation as an Int extension. Will generate random numbers in range from..<to
public extension Int {
static func random(from: Int, to: Int) -> Int {
guard to > from else {
assertionFailure("Can not generate negative random numbers")
return 0
}
return Int(arc4random_uniform(UInt32(to - from)) + UInt32(from))
}
}
This is how I get a random number between 2 int's!
func randomNumber(MIN: Int, MAX: Int)-> Int{
var list : [Int] = []
for i in MIN...MAX {
list.append(i)
}
return list[Int(arc4random_uniform(UInt32(list.count)))]
}
usage:
print("My Random Number is: \(randomNumber(MIN:-10,MAX:10))")
Another option is to use GKMersenneTwisterRandomSource from GameKit. The docs say:
A deterministic pseudo-random source that generates random numbers
based on a mersenne twister algorithm. This is a deterministic random
source suitable for creating reliable gameplay mechanics. It is
slightly slower than an Arc4 source, but more random, in that it has a
longer period until repeating sequences. While deterministic, this is
not a cryptographic random source. It is however suitable for
obfuscation of gameplay data.
import GameKit
let minValue = 0
let maxValue = 100
var randomDistribution: GKRandomDistribution?
let randomSource = GKMersenneTwisterRandomSource()
randomDistribution = GKRandomDistribution(randomSource: randomSource, lowestValue: minValue, highestValue: maxValue)
let number = randomDistribution?.nextInt() ?? 0
print(number)
Example taken from Apple's sample code: https://github.com/carekit-apple/CareKit/blob/master/CareKitPrototypingTool/OCKPrototyper/CareKitPatient/RandomNumberGeneratorHelper.swift
I'm late to the party 🤩🎉
Using a function that allows you to change the size of the array and the range selection on the fly is the most versatile method. You can also use map so it's very concise. I use it in all of my performance testing/bench marking.
elements is the number of items in the array
only including numbers from 0...max
func randArr(_ elements: Int, _ max: Int) -> [Int] {
return (0..<elements).map{ _ in Int.random(in: 0...max) }
}
Code Sense / Placeholders look like this.
randArr(elements: Int, max: Int)
10 elements in my array ranging from 0 to 1000.
randArr(10, 1000) // [554, 8, 54, 87, 10, 33, 349, 888, 2, 77]
you can use this in specific rate:
let die = [1, 2, 3, 4, 5, 6]
let firstRoll = die[Int(arc4random_uniform(UInt32(die.count)))]
let secondRoll = die[Int(arc4random_uniform(UInt32(die.count)))]
Lets Code with Swift for the random number or random string :)
let quotes: NSArray = ["R", "A", "N", "D", "O", "M"]
let randomNumber = arc4random_uniform(UInt32(quotes.count))
let quoteString = quotes[Int(randomNumber)]
print(quoteString)
it will give you output randomly.
Don't forget that some numbers will repeat! so you need to do something like....
my totalQuestions was 47.
func getRandomNumbers(totalQuestions:Int) -> NSMutableArray
{
var arrayOfRandomQuestions: [Int] = []
print("arraySizeRequired = 40")
print("totalQuestions = \(totalQuestions)")
//This will output a 40 random numbers between 0 and totalQuestions (47)
while arrayOfRandomQuestions.count < 40
{
let limit: UInt32 = UInt32(totalQuestions)
let theRandomNumber = (Int(arc4random_uniform(limit)))
if arrayOfRandomQuestions.contains(theRandomNumber)
{
print("ping")
}
else
{
//item not found
arrayOfRandomQuestions.append(theRandomNumber)
}
}
print("Random Number set = \(arrayOfRandomQuestions)")
print("arrayOutputCount = \(arrayOfRandomQuestions.count)")
return arrayOfRandomQuestions as! NSMutableArray
}
look, i had the same problem but i insert
the function as a global variable
as
var RNumber = Int(arc4random_uniform(9)+1)
func GetCase(){
your code
}
obviously this is not efficent, so then i just copy and paste the code into the function so it could be reusable, then xcode suggest me to set the var as constant so my code were
func GetCase() {
let RNumber = Int(arc4random_uniform(9)+1)
if categoria == 1 {
}
}
well thats a part of my code so xcode tell me something of inmutable and initialization but, it build the app anyway and that advice simply dissapear
hope it helps

Initializing MIDIMetaEvent structure

I am struggling to initialize the MIDIMetaEvent structure found in MusicPlayer.h with swift The header file defines the structure as follows:
struct MIDIMetaEvent {
var metaEventType: UInt8
var unused1: UInt8
var unused2: UInt8
var unused3: UInt8
var dataLength: UInt32
var data: (UInt8)
}
Which seems fairly straightforward up until that 'data' member. Is that a 1 element tuple definition? I can easily initialize all other struct elements but have tried in vain to set 'data' to anything else than a single value. In my code I used an UInt8 array called myData and attempted to init the structure like so:
var msg = MIDIMetaEvent(
metaEventType : UInt8(0x7F),
unused1 : UInt8(0),
unused2 : UInt8(0),
unused3 : UInt8(0),
dataLength : UInt32(myData.count),
data : UnsafeBufferPointer<UInt8>(start: UnsafePointer<UInt8>(myData), count:myData.count) )
But the compiler is not happy with this and complains about "UnsafeBufferPointer no convertible to UInt8". If I simply set data to a single value but set dataLength to a value more than 1, the resulting MIDIEventData shows that the first value in the event is what I stuck in 'data' followed by gibberish data bytes in accordance with 'dataLength' bytes. So clearly 'data' is seen as some sort of continuous memory.
So how do I set that 'data' element to UInt8 elements from an array?
The AudioToolbox framework defines MIDIMetaEvent as
typedef struct MIDIMetaEvent
{
UInt8 metaEventType;
UInt8 unused1;
UInt8 unused2;
UInt8 unused3;
UInt32 dataLength;
UInt8 data[1];
} MIDIMetaEvent;
where data[1] is actually used as a "variable length array".
In (Objective-)C one can just allocate a pointer to a memory block of the
actually needed size:
MIDIMetaEvent *mep = malloc(sizeof(MIDIMetaEvent) + data.count);
Swift is more strict with pointer casts and fixed size arrays are mapped to
Swift tuples (which can be cumbersome to handle with).
The following utility class shows how this could be solved:
class MyMetaEvent {
private let size: Int
private let mem : UnsafeMutablePointer<UInt8>
let metaEventPtr : UnsafeMutablePointer<MIDIMetaEvent>
init(type: UInt8, data: [UInt8]) {
// Allocate memory of the required size:
size = sizeof(MIDIMetaEvent) + data.count
mem = UnsafeMutablePointer<UInt8>.alloc(size)
// Convert pointer:
metaEventPtr = UnsafeMutablePointer(mem)
// Fill data:
metaEventPtr.memory.metaEventType = type
metaEventPtr.memory.dataLength = UInt32(data.count)
memcpy(mem + 8, data, UInt(data.count))
}
deinit {
// Release the allocated memory:
mem.dealloc(size)
}
}
Then you can create an instance with
let me = MyMetaEvent(type: 0x7F, data: myData)
and pass me.metaEventPtr to the Swift functions taking a UnsafePointer<MIDIMetaEvent>
argument.
Update for Swift 3/4:
Simply converting a pointer to a different type is no longer possible,
it must be "rebound":
class MyMetaEvent {
private let size: Int
private let mem: UnsafeMutablePointer<UInt8>
init(type: UInt8, data: [UInt8]) {
// Allocate memory of the required size:
size = MemoryLayout<MIDIMetaEvent>.size + data.count
mem = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
mem.initialize(to: 0, count: size)
// Fill data:
mem.withMemoryRebound(to: MIDIMetaEvent.self, capacity: 1) { metaEventPtr in
metaEventPtr.pointee.metaEventType = type
metaEventPtr.pointee.dataLength = UInt32(data.count)
memcpy(&metaEventPtr.pointee.data, data, data.count)
}
}
deinit {
// Release the allocated memory:
mem.deallocate(capacity: size)
}
func withMIDIMetaEventPtr(body: (UnsafePointer<MIDIMetaEvent>) -> Void) {
mem.withMemoryRebound(to: MIDIMetaEvent.self, capacity: 1) { metaEventPtr in
body(metaEventPtr)
}
}
}
Create an instance with custom data:
let me = MyMetaEvent(type: 0x7F, data: ...)
Pass to a function taking a UnsafePointer<MIDIMetaEvent> argument:
me.withMIDIMetaEventPtr { metaEventPtr in
let status = MusicTrackNewMetaEvent(track, 0, metaEventPtr)
}

Resources