First : what I am trying to do is find devices connected to a mac the same way calling
ls /dev/tty.usbmodem*
in Terminal does
but by using IOKit
Second, here is my code :
#IBAction func testPressed(sender: AnyObject) {
var portIterator: io_iterator_t = 0
let kernResult = findSerialDevices(kIOSerialBSDModemType, serialPortIterator: &portIterator)
if kernResult == KERN_SUCCESS {
printSerialPaths(portIterator)
}
}
func findSerialDevices(deviceType: String, inout serialPortIterator: io_iterator_t ) -> kern_return_t {
var result: kern_return_t = KERN_FAILURE
var classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue).takeUnretainedValue()
var classesToMatchDict = (classesToMatch as NSDictionary) as Dictionary<String, AnyObject>
classesToMatchDict[kIOSerialBSDTypeKey] = deviceType
let classesToMatchCFDictRef = (classesToMatchDict as NSDictionary) as CFDictionaryRef
result = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatchCFDictRef, &serialPortIterator);
return result
}
func printSerialPaths(portIterator: io_iterator_t) {
var serialService: io_object_t
do {
serialService = IOIteratorNext(portIterator)
if (serialService != 0) {
let key: CFString! = "IOCalloutDevice"
let bsdPathAsCFtring: AnyObject? = IORegistryEntryCreateCFProperty(serialService, key, kCFAllocatorDefault, 0).takeUnretainedValue()
var bsdPath = bsdPathAsCFtring as String?
if let path = bsdPath {
println(path)
}
}
} while serialService != 0;
}
When I run this in a command line tool (new project > os x > command line tool) it works well. (I basically write the same code only the four lines in the 'testPressed' function are not in an IBAction)
console output :
/dev/cu.Bluetooth-Modem
/dev/cu.usbmodem1411
When I run it from a cocoa mac application, it crashes after correctly executing the code :
/dev/cu.Bluetooth-Modem
/dev/cu.usbmodem1411
serialTests(40925,0x7fff77354300) malloc: *** error for object 0x61000003243c: Invalid pointer dequeued from free list
*** set a breakpoint in malloc_error_break to debug
(lldb)
I've researched this, googled the error, read the IOKit fundamentals app developer's guide, re-wrote the code in a separate project to make sure there wasn't something wrong in the other project I didn't notice.
And I still can't fix the bug
Related
I'm hoping someone may be able to help i'm using Xcode 8 and swift 3
I have a playground file Xcode 7 swift 2 that involves a Midi callback for Midi Input everything works fine in 7
I tried a conversion to 8 and it brought up errors regarding memory and a few name changes mostly of what i believe to be non serious i also redefined the infinite loop using PlaygroundSupport
However the error i cannot get over involves MyMIDIReadProc at
MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);
The error says
Cannot convert value of type '(pktList: UnsafePointer, readProcRefCon: UnsafeMutablePointer, srcConnRefCon: UnsafeMutablePointer) -> Void' to expected argument type 'MIDIReadProc' (aka '#convention(c) (UnsafePointer, Optional>, Optional>) -> ()')
My understanding is that it needs a #convention(c) wrapper of some description inserted. I think i'm on the right track because you can wrap a function but my knowledge of where to put it has run out. Again i was hoping some one might be able to advise
Thanks for reading
apologies for any bad language as i'm self taught
Here is the original Xcode 7 code
import Cocoa
import CoreMIDI
import XCPlayground
func getDisplayName(obj: MIDIObjectRef) -> String
{
var param: Unmanaged<CFString>?
var name: String = "Error";
let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, ¶m)
if err == OSStatus(noErr)
{
name = param!.takeRetainedValue() as String
}
return name;
}
func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
{
let packetList:MIDIPacketList = pktList.memory;
let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(COpaquePointer(srcConnRefCon)).memory;
print("MIDI Received From Source: \(getDisplayName(srcRef))");
var packet:MIDIPacket = packetList.packet;
for _ in 1...packetList.numPackets
{
let bytes = Mirror(reflecting: packet.data).children;
var dumpStr = "";
// bytes mirror contains all the zero values in the ridiulous packet data tuple
// so use the packet length to iterate.
var i = packet.length;
for (_, attr) in bytes.enumerate()
{
dumpStr += String(format:"$%02X ", attr.value as! UInt8);
--i;
if (i <= 0)
{
break;
}
}
print(dumpStr)
packet = MIDIPacketNext(&packet).memory;
}
}
var midiClient: MIDIClientRef = 0;
var inPort:MIDIPortRef = 0;
var src:MIDIEndpointRef = MIDIGetSource(0);
MIDIClientCreate("MidiTestClient", nil, nil, &midiClient);
MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);
MIDIPortConnectSource(inPort, src, &src);
// Keep playground running
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true;
And here is the Xcode 8 code converted
var str = "Hello, playground"
import Cocoa
import CoreMIDI
import XCPlayground
import PlaygroundSupport
func getDisplayName(obj: MIDIObjectRef) -> String
{
var param: Unmanaged<CFString>?
var name: String = "Error";
let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, ¶m)
if err == OSStatus(noErr)
{
name = param!.takeRetainedValue() as String
}
return name;
}
func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
{
let packetList:MIDIPacketList = pktList.pointee;
let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(OpaquePointer(srcConnRefCon)).pointee;
print("MIDI Received From Source: \(getDisplayName(obj: srcRef))");
var packet:MIDIPacket = packetList.packet;
for _ in 1...packetList.numPackets
{
let bytes = Mirror(reflecting: packet.data).children;
var dumpStr = "";
var i = packet.length;
for (_, attr) in bytes.enumerated()
{
dumpStr += String(format:"$%02X ", attr.value as! UInt8);
i -= 1;
if (i <= 0)
{
break;
}
}
print(dumpStr)
packet = MIDIPacketNext(&packet).pointee;
}
}
var midiClient: MIDIClientRef = 0;
var inPort:MIDIPortRef = 0;
var src:MIDIEndpointRef = MIDIGetSource(0);
MIDIClientCreate("MidiTestClient", nil, nil, &midiClient);
MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);
MIDIPortConnectSource(inPort, src, &src);
PlaygroundPage.current.needsIndefiniteExecution = true
Pointer types are drastically changed in Swift 3. Many C-based APIs' signatures are changed accordingly.
Following those changes manually would be painful. You can make Swift work for you, with a little modification.
Try changing the function header:
func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
{
to a closure declaration:
let MyMIDIReadProc: MIDIReadProc = {pktList, readProcRefCon, srcConnRefCon in
Swift infers argument types perfectly in this style.
You may need to fix pointer type conversion:
let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(OpaquePointer(srcConnRefCon)).pointee;
to something like this:
//I'm not sure using `!` is safe here...
let srcRef: MIDIEndpointRef = UnsafeMutablePointer(srcConnRefCon!).pointee
(By the way, the equivalent part in your Xcode 7 code is a little bit redundant. You have no need to use intermediate COpaquePointer there.)
In Swift 3, pointers cannot be nil, and nullable pointers are represented with Optionals. You may need many other fixes to work with C-based APIs in Swift 3.
OOPer is pointing (ahem) you in the right direction. Here is a blog post on using Swift 3 Core MIDI along with a working github repo.
Assuming that you're working with CoreMIDI 1.3 or later, you may have more luck using MIDIInputPortCreateWithBlock instead of MIDIInputPortCreate.
This method takes a Swift block as a parameter instead of requiring an #convention(c) function reference, making it more amenable to use within methods belonging to Swift classes, e.g.:
public func midiReadBlock(ptr: UnsafePointer<MIDIPacketList>, _: UnsafeMutableRawPointer?) -> Void {
let list: MIDIPacketList = ptr.pointee
...
}
You may also find these two extensions useful.
This one (derived from here) allows you to iterate directly over a MIDIPacketList using for pkt in list:
extension MIDIPacketList: Sequence {
public func makeIterator() -> AnyIterator<MIDIPacket> {
var iterator: MIDIPacket?
var nextIndex: UInt32 = 0
return AnyIterator {
nextIndex += 1
if nextIndex > self.numPackets { return nil }
if iterator != nil {
iterator = withUnsafePointer(to: &iterator!) { MIDIPacketNext($0).pointee }
} else {
iterator = self.packet;
}
return iterator
}
}
}
and this one adds a method to a MIDIPacket to extract the contents as a [UInt8] instead of having to use the really broken tuple syntax:
extension MIDIPacket {
public var asArray: [UInt8] {
let mirror = Mirror(reflecting: self.data)
let length = Int(self.length)
var result = [UInt8]()
result.reserveCapacity(length)
for (n, child) in mirror.children.enumerated() {
if n == length {
break
}
result.append(child.value as! UInt8)
}
return result
}
}
After an introduction to Javascript, I'm trying to tackle OSX/iOS programming by creating some simple tools to scratch my own itches.
However, right from the jump I hit a roadblock.
I found two examples that should work.
https://github.com/hinderberg/ios-swift-kurs/blob/master/swift-intro/wallpaper.swift
https://www.snip2code.com/Snippet/196825/Swift-shell-script-to-randomize-wallpape
Here's the second:
#!/usr/bin/env xcrun swift
import Foundation
import AppKit
let imagesDir = "/Users/david/Dropbox/Graphics/Wallpaper-HD/"
var err: NSError?
let fs = NSFileManager.defaultManager()
let filenames = fs.contentsOfDirectoryAtPath(imagesDir, error: &err) as [String]?
if let error = err {
NSLog(error.localizedDescription)
} else {
let imagenames = filenames!.filter { $0.hasSuffix(".jpg") || $0.hasSuffix("png") }
let ir = Int(arc4random_uniform(UInt32(imagenames.count)))
let imgurl = NSURL.fileURLWithPath(imagesDir + imagenames[ir])
let workspace = NSWorkspace.sharedWorkspace()
let screen = NSScreen.mainScreen()
let ok : Bool = workspace.setDesktopImageURL( imgurl!, forScreen: screen!, options: nil, error: nil )
if ok {
println( "New wallpaper: " + imagenames[ir] )
} else {
println("Oops!")
}
}
This didn't work in XCode 7 beta 3.
Hoping to reduce to the essentials, I arrived at:
#!/usr/bin/env xcrun swift
import Foundation
import AppKit
let imagesDir = "/Users/josh/Downloads/"
let singleImage = "/Users/josh/Downloads/xlarge.png"
let imgurl = NSURL.fileURLWithPath(singleImage)
let workspace = NSWorkspace.sharedWorkspace()
let screen = NSScreen.mainScreen()
let ok : Bool = workspace.setDesktopImageURL( imgurl, forScreen: screen!, options: nil, error: nil )
if ok {
print( "New wallpaper set!" )
} else {
print("Oops!")
}
And saved as the file wallpaper.swift.
On execution, the error is:
./wallpaper.swift:17:49: error: extra argument 'error' in call
let ok : Bool = workspace.setDesktopImageURL( imgurl, forScreen: screen!, options: nil, error: nil )
And now I'm completely stuck...
I've tried referring to NSWorkspace and NSScreen documentation as well as running through playground, but it's beyond my current skills.
Removing the extra argument it complains about (error: nil) simply gives a different error:
./wallpaper.swift:13:31: error: cannot invoke 'setDesktopImageURL' with an argument list of type '(NSURL, forScreen: NSScreen?, options: nil)'
let ok : Bool = workspace.setDesktopImageURL( imgurl, forScreen: screen, options: nil )
Where is the code failing, and how can I understand how to make it work properly?
In your example you're passing nil as options to the method.
I guess it worked before but now in the comments you showed the current method signature:
(url: NSURL, forScreen screen: NSScreen, options: [String : AnyObject]) throws
We see that options should be a non-Optional Dictionary.
It means you can't use nil anymore for the options parameter: if you don't have options, just pass an empty Dictionary.
Also, now in Swift 2, this method doesn't return a Bool anymore, it throws.
Meaning you have to use it with do try catch:
do {
let imgurl = NSURL.fileURLWithPath(singleImage)
let workspace = NSWorkspace.sharedWorkspace()
if let screen = NSScreen.mainScreen() {
try workspace.setDesktopImageURL(imgurl, forScreen: screen, options: [:])
}
} catch {
print(error)
}
Updated example for Swift 3:
do {
let imgurl = NSURL.fileURL(withPath: singleImage)
let workspace = NSWorkspace.shared()
if let screen = NSScreen.main() {
try workspace.setDesktopImageURL(imgurl, for: screen, options: [:])
}
} catch {
print(error)
}
For those of us using Xamarin Mac, this can be achieved like so:
string filepath = "/Users/you/Desktop/sweet-wallpaper.jpg";
var workspace = NSWorkspace.SharedWorkspace;
var screen = NSScreen.MainScreen;
NSUrl url = NSUrl.FromFilename(filepath);
NSDictionary options = new NSDictionary();
NSError errorContainer = new NSError();
workspace.SetDesktopImageUrl(url, NSScreen.MainScreen, options, errorContainer);
Updated version for Swift 5.x:
do {
let imageURL = URL(fileURLWithPath: "/path/to/image")
if let screen = NSScreen.main {
try NSWorkspace.shared.setDesktopImageURL(imageURL, for: screen, options: [:])
}
} catch {
print(error)
}
I'm trying to make an application that communicates with a USB device about the same way I use the screen command on Terminal.
To make my question easier to understand, This is what I normally do in Terminal :
command :
ls /dev/tty.usb*
returns :
/dev/tty.usbmodem1411 /dev/tty.usbmodem1451
Next, I call :
screen /dev/tty.usbmodem1411
After this, I can send commands to the device (type in 'U' for example, get a response)
I'm trying to do this from Xcode now.
Using IOKit, I've managed to execute what is equivalent to the first command that returns the list of usb ports :
/dev/tty.usbmodem1411 /dev/tty.usbmodem1451
This is the code :
#IBAction func testPressed(sender: AnyObject) {
var portIterator: io_iterator_t = 0
let kernResult = findSerialDevices(kIOSerialBSDModemType, serialPortIterator: &portIterator)
if kernResult == KERN_SUCCESS {
printSerialPaths(portIterator)
}
}
func findSerialDevices(deviceType: String, inout serialPortIterator: io_iterator_t ) -> kern_return_t {
var result: kern_return_t = KERN_FAILURE
var classesToMatch = IOServiceMatching(kIOSerialBSDServiceValue).takeUnretainedValue()
var classesToMatchDict = (classesToMatch as NSDictionary) as Dictionary<String, AnyObject>
classesToMatchDict[kIOSerialBSDTypeKey] = deviceType
let classesToMatchCFDictRef = (classesToMatchDict as NSDictionary) as CFDictionaryRef
result = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatchCFDictRef, &serialPortIterator);
return result
}
func printSerialPaths(portIterator: io_iterator_t) {
var serialService: io_object_t
do {
serialService = IOIteratorNext(portIterator)
if (serialService != 0) {
let key: CFString! = "IOCalloutDevice"
let bsdPathAsCFtring: AnyObject? = IORegistryEntryCreateCFProperty(serialService, key, kCFAllocatorDefault, 0).takeUnretainedValue()
var bsdPath = bsdPathAsCFtring as String?
if let path = bsdPath {
println(path)
}
}
} while serialService != 0;
}
}
Now, even after reading Apple's IOKit manual, I can't move forward.
How can I start sending commands using IOKit ?
See Apple Performing Serial I/O sample project.
I have a piece of code that has been running smoothly since I created it, that has suddenly begun to crash every time I run my app. I keep getting EXC_BREAKPOINT that highlights a line in my Thread 1 that states: Swift._getImplicitlyUnwrappedOptionalValue. I've tried adding breakpoints to catch the suspect code within my method, but nothing turns up and I just keep getting this error. I've been at this for a while now, and I'm pretty stumped as to what is going on and how I'm supposed to fix it. Any help is appreciated! Below I've included a screenshot of the error as well as the method I'm trying to call that produces the error. Thanks!
#IBAction func nextPhoto(sender: UISwipeGestureRecognizer)
{
self.deleteResponseMessage(self)
if photoObjects.count == 0
{
var image:UIImage = UIImage(contentsOfFile: "launchImageTall")
feedView.image = image
}
else
{
userInfo.hidden = false
var content:PFObject = photoObjects[0] as PFObject
var recipients = content["recipients"] as NSMutableArray
var userImageFile = content["imageFile"] as PFFile
userImageFile.getDataInBackgroundWithBlock { (imageData:NSData!, error:NSError!) -> Void in
if error == nil
{
var contentImage = UIImage(data: imageData)
self.feedView.image = contentImage
}
}
var profilePicImageFile = content["senderProfilePic"] as PFFile
profilePicImageFile.getDataInBackgroundWithBlock({ (imageData:NSData!, error:NSError!) -> Void in
if error == nil
{
var picture = UIImage(data: imageData)
self.senderProfilePic.image = picture
}
})
var username = content["senderUsername"] as NSString
senderUsername.text = username
var photoCaption = content["photoCaption"] as NSString
senderMessage.text = photoCaption
senderObjectId = content["senderObjectId"] as NSString
for var i=0;i<photoObjects.count-1;i++
{
photoObjects[i] = photoObjects[i+1]
}
if recipients.count == 1
{
content.deleteInBackground()
}
else
{
recipients.removeObject(currentUserObjectId!)
content.setObject(recipients, forKey: "recipients")
content.saveInBackground()
}
}
}
Did you update Xcode recently. Apple is busy updating their cocoa libraries. Every return value was explicitly being unwrapped (like return String!). Now they are going through every function and evaluating whether it should return an instance (return String) or an optional (String?).
So check your code for optionals and remove those ! or ?.
At least that was the case for me with every Xcode update.
I'm used to write code with early return/golden path in Objective-C. I tried this approach in Swift, and noticed that early return comes at the expense of using the forced unwrapping operator (!) when optionals are involved.
Take a method that calculates the size of a directory. First, the golden path version:
private func calculateSize_GoldenPath(directory:String) -> UInt64 {
let fileManager = NSFileManager.defaultManager()
var error : NSError?
var contents = fileManager.contentsOfDirectoryAtPath(directory, error: &error) as [String]?
if contents == nil {
NSLog("Failed to list directory with error \(error)")
return 0
}
var size : UInt64 = 0
for pathComponent in contents! {
let path = directory.stringByAppendingPathComponent(pathComponent)
let attributes : NSDictionary? = fileManager.attributesOfItemAtPath(path, error: &error)
if (attributes == nil) {
NSLog("Failed to read file size of \(path) with error \(error)")
continue
}
size += attributes!.fileSize()
}
return size;
}
Notice how I'm using the ! operator both for the contents and attributes variables.
I'm assuming that overusing the ! operator kind of defeats the purpose of optionals and the type safety they bring. This is how I feel the above method should be coded in Swift to avoid forced unwrapping:
private func calculateSize_IfLet(directory:String) -> UInt64 {
let fileManager = NSFileManager.defaultManager()
var error : NSError?
if let contents = fileManager.contentsOfDirectoryAtPath(directory, error: &error) as? [String] {
var size : UInt64 = 0
for pathComponent in contents {
let path = directory.stringByAppendingPathComponent(pathComponent)
if let attributes : NSDictionary = fileManager.attributesOfItemAtPath(path, error: &error) {
size += attributes.fileSize()
} else {
NSLog("Failed to read file size of \(path) with error \(error)")
}
}
return size
} else {
NSLog("Failed to list directory with error \(error)")
return 0
}
}
However, by using if let I can't do early return anymore. If some methods don't use early return and some do, then I end up with a project with mixed coding style.
My question is, is there a way to code in golden path style without resorting to forced unwrapping when optionals are involved?
Personally I would use extraction of methods, in this case extract the pathComponent section into a separate method thus avoiding the multiple indent and awkward code that mashes conceptually separate code together.
private func calculateSize_IfLet(directoryPath:String) -> UInt64 {
var size : UInt64 = 0
let fileManager = NSFileManager.defaultManager()
var error : NSError?
if let contents = fileManager.contentsOfDirectoryAtPath(directoryPath, error: &error) as? [String] {
size = self.calculateSizeOfDirectory(directoryPath, contents:contents)
} else {
NSLog("Failed to list directory with error \(error)")
}
return size
}
private func calculateSizeOfDirectory(directoryPath:String, contents:[String]) -> UInt64 {
var size : UInt64 = 0
for pathComponent in contents {
var error : NSError?
let fileManager = NSFileManager.defaultManager()
let path = directoryPath.stringByAppendingPathComponent(pathComponent)
if let attributes : NSDictionary = fileManager.attributesOfItemAtPath(path, error: &error) {
size += attributes.fileSize()
} else {
NSLog("Failed to read file size of \(path) with error \(error)")
}
}
return size
}