Below is my Swift code so far. Unfortunately the array onlineDspys doesn't get updated by CGGetOnlineDisplayList. Help appreciated.
main.swift
import Foundation
import CoreGraphics
var mainID = CGMainDisplayID()
println("ID is \(mainID)")
var dErr: CGError
let maxDisplays: UInt32 = 16
var onlineDspys: [CGDirectDisplayID] = [mainID]
var dspyCnt: UInt32 = 0
dErr = CGGetOnlineDisplayList(maxDisplays, &onlineDspys, &dspyCnt)
println("dspyCnt is \(dspyCnt)")
for currentDisplay in onlineDspys {
println("currentDisplay is \(currentDisplay)")
println("CGDisplayPixelsHigh(currentDisplay) is \(CGDisplayPixelsHigh(currentDisplay))")
println("CGDisplayPixelsWide(currentDisplay) is \(CGDisplayPixelsWide(currentDisplay))")
}
There are a couple issues here that are misleading you into believing that your onlineDspys array is not being updated.
The first problem is that you're actually pre-populating the first index of that array with the exact value that the CGGetOnlineDisplayList method call would set it to. If you instead prepopulated it with a value like 0, you'd see it's filling it in:
var onlineDspys: [CGDirectDisplayID] = [0]
The second problem is that CGGetOnlineDisplayList won't allocate memory for us. It can't call append on our array. We have to give it a block of memory to fill in the values. So, when we set up the variables we're going to pass in to the the function, we need to set them up more like this:
let maxDisplays: UInt32 = 16
var onlineDisplays = [CGDirectDisplayID](count: Int(maxDisplays), repeatedValue: 0)
var displayCount: UInt32 = 0
Now, our onlineDisplays is an array full of 16 zeros for CGGetOnlineDisplayList to fill in.
We call the function:
let dErr = CGGetOnlineDisplayList(maxDisplays, & onlineDisplays, & displayCount)
Now, the tricky bit... we don't want to waste time iterating over the parts of the array that didn't get filled in, so we make use of what the function filled into the displayCount variable:
for currentDisplay in onlineDisplays[0..<Int(displayCount)] {
print("currentDisplay is \(currentDisplay)")
print("CGDisplayPixelsHigh(currentDisplay) is \(CGDisplayPixelsHigh(currentDisplay))")
print("CGDisplayPixelsWide(currentDisplay) is \(CGDisplayPixelsWide(currentDisplay))")
}
The whole code snippet all together:
import Foundation
import CoreGraphics
var mainID = CGMainDisplayID()
print("ID is \(mainID)")
let maxDisplays: UInt32 = 16
var onlineDisplays = [CGDirectDisplayID](count: Int(maxDisplays), repeatedValue: 0)
var displayCount: UInt32 = 0
let dErr = CGGetOnlineDisplayList(maxDisplays, &onlineDisplays, &displayCount)
print("dspyCnt is \(displayCount)")
for currentDisplay in onlineDisplays[0..<Int(displayCount)] {
print("currentDisplay is \(currentDisplay)")
print("CGDisplayPixelsHigh(currentDisplay) is \(CGDisplayPixelsHigh(currentDisplay))")
print("CGDisplayPixelsWide(currentDisplay) is \(CGDisplayPixelsWide(currentDisplay))")
}
Related
I tested my code in Playground, but as the discussion points out, that Playground is debug configuration, once I put all those code in real app running, they don't make a big difference. Don't know about this debug/release thing before.
Swift performance related question, I need to loop through the pixel offset of images, first I attempted it in this way.
func p1() -> [[Int]]{
var offsets = [[Int]]()
for row in 0..<height {
var rowOffset = [Int]()
for col in 0..<width {
let offset = width * row + col
rowOffset.append(offset)
}
offsets.append(rowOffset)
}
return offsets
}
But it is very slow, I searched and found some code snippet loop through offset this way:
func p2() -> [[Int]]{
return (0..<height).map{ row in
(0..<width).map { col in
let offset = width * row + col
return offset
}
}
}
So I tested if I use function p1 and p2 to loop through height = 128 and width = 128 image , p1 is 18 times slower than p2, why p1 is so slow compared with p2 ? also I'm wondering is there any other faster approach for this task?
The most obvious reason why the map approach is faster is because map allocates the array capacity up front (since it knows how many elements will be in the resulting array). You can do this too in your code by calling ary.reserveCapacity(n) on your arrays, e.g.
func p1() -> [[Int]]{
var offsets = [[Int]]()
offsets.reserveCapacity(height) // NEW LINE
for row in 0..<height {
var rowOffset = [Int]()
rowOffset.reserveCapacity(width) // NEW LINE
for col in 0..<width {
let offset = width * row + col
rowOffset.append(offset)
}
offsets.append(rowOffset)
}
return offsets
}
I have found the issue. In order to make question focus on the issue, I edited and reformat the question.
History: Previously I was using NSData instead of Data. I should use Data so I changed the question. Using Data does not solve the problem. I reformat it a little bit to make the problem stands out. See answer if you have the same issue
===========
I am using Swift 3.1
I want to convert the sub-array of a byte array into Int.
This is what I do here.
// I am extracting every 4 from the dataBytes and convert it to int
var xDataArray = dataBytes[8...11]
let xData = Data(buffer: UnsafeBufferPointer(start: &xDataArray, count: xDataArray.count))
var xVal: Int32 = xData.withUnsafeBytes { $0.pointee }
xVal = Int32(bigEndian: xVal)
var yDataArray = dataBytes[12...15]
let yData = Data(buffer: UnsafeBufferPointer(start: &yDataArray, count: yDataArray.count))
var yVal: Int32 = yData.withUnsafeBytes { $0.pointee }
yVal = Int32(bigEndian: yVal)
The xVal and yVal are the same and they seem to be very large random number.
I solved the issue.
I am using dataBytes[8...11] to get the subarray and this is the place where it get me the same result of the NSData.
Instead I use xDataArray:[UInt8] = [dataBytes[8], dataBytes[9], dataBytes[10], dataBytes[11]]
var xDataArray: [UInt8] = [dataBytes[8], dataBytes[9], dataBytes[10], dataBytes[11]]
let xData = NSData(bytes: &xDataArray, length: xDataArray.count)
var xVal: Int32 = 0
xData.getBytes(&xVal, length: MemoryLayout<Int32>.size)
xVal = Int32(bigEndian: xVal)
var yDataArray: [UInt8] = [dataBytes[12], dataBytes[13], dataBytes[14], dataBytes[15]]
let yData = NSData(bytes: &yDataArray, length: yDataArray.count)
var yVal: Int32 = 0
yData.getBytes(&yVal, length: MemoryLayout<Int32>.size)
yVal = Int32(bigEndian: yVal)
NOTE:
If the Int gets from the Server is 32 Bit, Use Int32 instead of Int
For communicating with a BLE characteristic, I have a Swift struct that looks like:
struct Packet {
var control1:UInt8 = 0
var control2:UInt8 = 0
var payload:(UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8,UInt8) = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
init(control1:UInt8, control2:UInt8) {
self.control1 = control1
self.control2 = control2
}
}
I have payload defined as a tuple, because that seems to be the only way to have an array (of bytes in this case) of fixed size embedded in a Swift struct. Verbose, but whatever.
I have a big ol' source:[UInt8] that I want to pull swatches of into that Packet struct, so I can send them via BLE to the remote device. When I do:
var packet = Packet(control1: self.pageIndex, control2: sentenceIndex)
let offset = (Int(self.pageIndex) * self.pageSize) + (Int(sentenceIndex) * self.sentenceSize)
let limit = offset + self.sentenceSize
packet.payload = self.source[offset..<limit]
For the last line, I get the rather confusing error:
Cannot subscript a value of type '[UInt8]'
Cryptic I say, because it actually can. If I take the assignment to the packet.payload out, it has no problem subscripting the value.
What I'm really interested in at a higher level, is how one puts together a struct with a fixed size array of bytes, and then copies swatches of a large buffer into those. I would like to both understand the above, as well as know how to solve my problem.
UPDATE:
I ended up backing up a little, influenced by both answers below, and rethinking. My main driving force was that I wanted a simple/clever way to have convert a struct with an internal array to/from NSData, primary in BLE communications. What I ended up doing was:
struct Packet {
var pageIndex:UInt8 = 0
var sentenceIndex:UInt8 = 0
var payload:ArraySlice<UInt8> = []
var nsdata:NSData {
let bytes:[UInt8] = [self.pageIndex, self.sentenceIndex] + self.payload
return NSData(bytes: bytes, length: bytes.count)
}
}
Not the most efficient because I have to create the intermediate [UInt8] array, but I decided that a simple way to convert didn't exist, that I'd have to do things with as conversions or memcpy and friends.
I'm not sure which of the two below to mark as an answer, since both influenced what I ended up with.
There are two ugly/simple solutions:
To assign each member of the tuple separately:
var offset = ...
packet.payload = (source[offset++], source[offset++], ... , source[offset++])
To just copy the raw memory (recommended)
var values = Array(source[offset..<limit])
memcpy(&packet.payload, &values, sentenceSize)
Note that it's possible to create an array from a tuple:
func tupleToArray<T>(tuple: Any, t: T.Type) -> [T] {
return Mirror(reflecting: tuple).children.flatMap{ $0.value as? T }
}
tupleToArray((1, 2, 3, 4, 5), t: Int.self) // [1, 2, 3, 4, 5]
But the other way around doesn't work, as Swift's reflection is read-only.
Another much more complicated but more beautiful solution would be to use Dependent Types, which enables you to have arrays with compile-time known length. Check out this great blog post, in which he also mentions this post on the Apple Developer forums which is basically what you'd need:
let vector = 3.0 ⋮ 4.0 ⋮ 5.0 // [3.0, 4.0, 5.0]
vector[1] // 4.0
vector.count // 3
sizeofValue(vector) // 3 * 8 ( same size as a tuple with 3 elements)
First of all don't use tuples to create contiguous arrays of memory. Go ahead and use the [UInt8] type. I would recommend using a stride function to create your indices for you like this. You will have to handle the case of your data source not being a multiple of the Packet payload size.
struct Packet {
var control1: UInt8 = 0
var control2: UInt8 = 0
static let size = 16
var payload = [UInt8].init(count: Packet.size, repeatedValue: 0)
init(control1: UInt8, control2: UInt8) {
self.control1 = control1
self.control2 = control2
}
}
// random values between 0...255
let blob = (0..<(Packet.size * 3)).map{_ in UInt8(arc4random_uniform(UInt32(UInt8.max)))}
for index in 0.stride(through: blob.count - 1, by: Packet.size) {
var packet = Packet(control1: 4, control2: 5)
packet.payload[0..<Packet.size] = blob[index..<index + Packet.size]
print(packet.payload)
}
As far as the cannot subscript error, I encountered that too. I suspect that this has changed recently. I was able to eliminate the error by matching the packet indice slice with the data source slice.
UPDATE
A commenter correctly pointed out that Packet structure contained a reference to an Array and therefore did not meet the OP's need. While I was focused more on iterating through a large data source using stride, here is an alternative using an untyped [UInt8] for such a simple data structure.
// payload size in count of UInt8
let size = 16
// field offsets
let control1 = 0
let control2 = 1
let payload = 2..<(2 + size)
// random values between 0...255
let blob = (0..<size * 3).map{_ in UInt8(arc4random_uniform(UInt32(UInt8.max)))}
for index in 0.stride(through: blob.count - 1, by: size) {
var buffer = [UInt8](count: 2 + size, repeatedValue: 0)
buffer[control1] = 255
buffer[control2] = 0
buffer[payload] = blob[index..<index + size]
let data = NSData(bytesNoCopy: &buffer, length: buffer.count, freeWhenDone: false)
// send data
}
I am learning how to build apps and working with Swift for this project.
I had a buddy help me pull data in from a website and it looks like he created classes with variables and mapped them to certain extensions (IE "Username") so when I call the variable data such as profile I would call it. The below uses luck_30 able to store "Stats.luck_30"
luck_30.text = profile.luck_30
So inside one of my variables that is in this "Profile" class is setup into an array. I can pull the array out of the class, but I can't seem to do for while statement replacing the [#] with a variable from the for command.
func aliveWorkers(profile: Profile) -> NSNumber{
var myworkers : Array = profile.workers!
//this test works and returns the proper value
var testworker: NSNumber = myworkers[0].alive!
println("The satus of the test worker is " + testworker.description)
/* This code is giving error "Could not find member alive" it does not ifor var
for ifor in myworkers{
var thisworker: NSNumber = myworkers[ifor].alive! as NSNumber
}
*/
return 42
}
Your variable ifor is not a counter, it is an actual object. You could do something like this:
for worker in myWorkers {
let workerIsAlive = worker.alive!
}
Alternatively, if you need the index,
for i in 0 ..< myWorkers.count {
let worker = myWorkers[i]
let workerIsAlive = worker.alive!
}
If you need both:
for (i, worker) in enumerate(myWorkers) {
let workerIsAlive = worker.alive!
}
And as a matter of style, I would stay away from NSNumber and use Int or Bool or whatever the data actually is. Also, it looks like the alive variable should not be optional, as you're unwrapping it everywhere. To avoid "mysterious" crashes later, you may want to think about making it a non-optional type.
when using a for in loop, your loop variable isn't an index, its the objects you're looping through. so..
func aliveWorkers() {
var myworkers = [1, 2, 3]
//this test works and returns the proper value
let testworker = myworkers[0]
print("The satus of the test worker is \(testworker)")
for ifor in myworkers {
print(ifor)
}
}
Notice a few things... you don't need to use + to concatenate those strings. you can just use string interpolation. \(variable) inserts the value of variable in the string.
Try to use let instead of var when you don't change the variable. You don't need to explicitly define type on variables either.
im new to using action script so i apologies if this wont make sense, the issue iam having is that the incoming bytes from my arduino are not being stored properly in an array. The bytes come in one at a time from my arduino and will be stored in an array in as3.
i have two values SF-F8-001, SF-F8-002 and SF-F8-003 etc... when i trace the incoming bytes i get this:
S
F
-
F
8
-
0
0
1
so when i look at that i realized i needed an array to store the byte as they come in however i have tried many different things but it hasnt worked
however this code below seems to get me close to my desired result
import flash.events.*;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.net.URLVariables;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequestMethod;
var ary:Array = new Array();
var bar_grab:Array = new Array();
var array:Array = new Array();
trace("__AS3 Example__");
var socket:Socket = new Socket("localhost",5331);
socket.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
function socketDataHandler(event:ProgressEvent):void
{
var str:String = String(socket.readUTFBytes(socket.bytesAvailable));
var b:String;
bar_grab.push(str);
b = bar_grab.join("");
boxtwo.text = b;
}
this code gets me this
SF-F8-001SF-F8-002SF-F8-003 etc...
however the result iam looking for is this
SF-F8-001,SF-F8-002,SF-F8-003 etc....
so if anyone could help me sort this out i will be grateful
thank you
If you know a priori how many characters each item will consist of you could read everything to string and get each individual item like that:
//Main string containing all items
var allString:String = "123456789";
//Number of chars in of item
var charsInItem = 3;
var item:String;
var index:int;
var resultArray:Array = new Array();
for(var i:int = 0; i < allString.length/charsInItem; i++)
{
index= i*charsInItem;
//traces name of one item
item = allString.slice(index, index+charsInItem);
resultArray.push(item);
trace(item);
}
//Output:
//123
//456
//789
If you don't know a number of chars in one item or it varies, I would suggest tweaking Arduino code and putting some sort of a marker in between every item. Like say a comma (,). Then your string would look something like this: "item1,item2,longerItem3". And you could split that string into array like that:
var array:Array = new Array();
var allString:String = "item1,item2,longerItem3";
//This splts string into array items using comma (,) as a seperator
array = allString.split(",");
for(var i:int = 0; i < array.length; i++)
{
//trace every array element
trace(array[i]);
}
//Output:
//item1
//item2
//longerItem3
I should add that even if you know a number of chars in one item I would still suggest using method nr.2.