For me personal hot spot over USB cable worked.Sometimes I have to disable WiFi on my phone as well.It was a bit harder if trying to record iPhone's screen using QuickTime:1. Connect QuickTime2. Enable Personal Hotspot3. Disable WiFi
Post
Replies
Boosts
Views
Activity
For me connect via network worked flawlessly on my home Wi-Fi, but I always wanted to go in the park and have the freedom of developing applications without the cable, where my iPhone provides Internet via its hotspot. Thanks to eskimo's advice, under devices, I selected connect via IP: 172.20.10.1 and now it just works.
It would be nice if Apple reconsiders the hotspot and allows wireless debugging and all the other useful features to work without the need of entering IP manually or looking for workarounds.
Fix:
cd /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/DeviceSupport
sudo ln -s 15.5 15.7
Explanation:
Xcode 13.4.1 contains DeviceSupport folders up to 15.5 and works with iOS 15.7 devices. 15.7 is missing in 14.0, it will try to use 15.6, which fails to prepare the iOS device for development. If we copy 15.5 to 15.7 or create a link, the 15.5 folder is used, which works for iOS 15.7. My iPhone 7 Plus is recognised instantly over the network, and
Developer menu appears in Settings.
Broken again in Xcode Version 15.0 (15A240d). USB works and the iPhone is successfully prepared for development. Network run destination is broken. Tested with iPhone 7 Plus iOS 15.7.9. If I run Xcode 14, the phone is automatically prepared for development over the network and I can run and debug apps.
Thanks, that's why there is a check: if value is negative, I set it to zero. The only case in which this could crash is if two instances of my function are ran concurrently, which does happen during heavy load, CMMotionManager seems to call my handler again before the previous instance returns. Even though there is little code after the check, the second instance could set value to negative, which would produce the crash. Then it was able to change it back to zero right before the debugger stopped the application. That last part got me confused. The solution was to use a local variable, that is checked and corrected. Moral of the story: always work with local copies of anything that should not be changed externally.
Cheers!
The traditional fix would be a mutex that protects value. That's not necessarily sufficient for correctness.
Indeed for correctness it is not. In C I would do atomic sub and fetch. There's also the question if it is worth switching to kernel space to lock a mutex on code that runs frequently and would not cause any noticeable side effects. In this case I would say no.
I guess that the "modern Swift / Apple way" to do this would involve a serial queue.
I just learned how to use Swift queues yesterday. 😊 Coming from C/C++ it took a day to bend my mind and get things running smoothly. Namely replacing a cached Path object in use by SwiftUI from a worker thread is a good way to trigger double free. Memory management in Swift might use some improvement. They relay on the assumption that you do everything on the main thread.
At my opinion, queues are an easy way to serialise activities or run a group of things concurrently. I wonder how efficient they are? First there is code to manage the queue, and then if an operation has to wait, a context switch is required to process another. Or does the whole queue stall? I've seen projects in Zephyr OS, where they create objects to pass data between tasks. It's handled in serialised work queues. And it's horribly slow, complex and prone to errors. When I designed nano RTOS, I figured I can make IO calls somewhere in between synchronous and asynchronous. In theory the calls might block, in practice they don't. The user can write simple linear code: receive, process, send all in one task. It does not drop data. The OS takes care of the rest.
I am surprised that this isn't what happens in the compiled code anyway. I.e. given your source code
I would expect the compiler to generate code that keeps v in a register through all of that and not read and write to the global variable location
Anyway, I suggest that you look at the generated code (if you can work out how to do that) and see if it is really doing what you think it is doing.
View disassembly would be my first thing on a development board 👍🏻
Yes, in C/C++ it is very easy to control if the data will be kept in a register or loaded again. I wonder if Swift can be told to do so?
Considering value is actually cnc.data.controller_gyro.value, a plain variable three ObservableObject classes deep (code below). And there are a couple of quick if checks, so the compiler may choose to load value again.
Maybe you have compiled with no optimisation? Maybe your real code is more complicated than what you've posted?
By default the iPhone run target is Debug, which should disable optimisations. I tried Release as well, and looked into the disassembly in both cases, but it is very hard for me to follow what ASM correspond to what Swift line. I usually have them side by side when debugging embedded boards, can I do this with Xcode? I get the impression value is loaded again. I write and debug Cortex-M ASM in kernel mode, but Swift seems to generate a lot of code for simple operations. If you wish I can post a screenshot?
That takes a queue on which it will invoke the callback. If you pass a serial queue there, you should not get concurrent calls.
In that case I should change my code to this
let queue = OperationQueue()
queue.name = "gyroscope"
queue.maxConcurrentOperationCount = 1
queue.qualityOfService = .userInteractive
motion.startGyroUpdates(to: queue, withHandler: gyro_handler)
How are you actually getting this gyro data?
Original implementation
class controller_gyro_t: ObservableObject
{
@Published var active: Bool = false
let start: TimeInterval = 0.20
let delay: TimeInterval = 0.045
let fast: TimeInterval = 0.00
var last: TimeInterval = 0
var timestamp: TimeInterval = 0
var value: Double = 0
var angle: UInt8 = 0
var ack: Bool = false
func stop()
{
if active
{
active = false
}
angle = 0
value = 0
}
}
struct ContentView: View
{
// ...
#if !os(macOS)
let motion = CMMotionManager()
#endif
func gyro_handler(data: CMGyroData?, err: Error?)
{
if cnc.data.stop || cnc.data.return_home
{
DispatchQueue.main.async
{
stop_controller()
}
return
}
if !cnc.data.controller_gyro.active
{
DispatchQueue.main.async
{
stop_controller_gyro()
}
return
}
if let gyro = data
{
let now = gyro.timestamp
let gyro_dt = now - cnc.data.controller_gyro.last
cnc.data.controller_gyro.last = now
if gyro_dt > cnc.data.controller_gyro.start
{
// the last packet was very long ago
// usually the first sample when we start receiving updates
return
}
// rotation rate: rad/s
var value = cnc.data.controller_gyro.value - gyro.rotationRate.z * gyro_dt * angle_rad_to_deg
if value < angle_min
{
value = angle_min
}
else if value > angle_max
{
value = angle_max
}
cnc.data.controller_gyro.value = value
if cnc.data.controller_gyro.ack
{
cnc.data.controller_gyro.ack = false
cnc.data.controller_gyro.timestamp -= cnc.data.controller_gyro.fast
}
if cnc.data.controller_gyro.timestamp > now
{
return
}
let angle = UInt8(value.rounded())
if cnc.data.controller_gyro.angle != angle
{
cnc.data.controller_gyro.angle = angle
cnc.data.controller_gyro.timestamp = now.advanced(by: cnc.data.controller_gyro.delay)
let a = "a\(angle)"
send_no_log(a)
DispatchQueue.main.async
{
cnc.data.angle = Float(angle)
}
}
}
}
func btn_gyro_control() -> some View
{
Button
{
haptic_feedback()
if cnc.data.controller_gyro.active
{
stop_controller()
send_cmd(cmd_stop)
}
else
{
stop_controller()
cnc.data.stop = false
cnc.data.return_home = false
cnc.data.controller_gyro.active = true
cnc.data.controller_gyro.value = angle_mid
cnc.data.controller_gyro.angle = UInt8(angle_min)
send_cmd("u")
#if !os(macOS)
if motion.isGyroAvailable
{
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + cnc.data.controller_gyro.start)
{
motion.startGyroUpdates(to: OperationQueue(), withHandler: gyro_handler)
}
}
#endif
}
} label:
{
Image(systemName: cnc.data.controller_gyro.active ? "gyroscope" : "gyroscope")
.button_style_image(
cnc.connected ? cnc.data.controller_gyro.active ? colour_store : colour_btn : colour_disabled,
fg: cnc.connected ? .white : colour_btn_fg_disabled
)
}
.font(.system(size: size_font_img, design: Font.Design.rounded))
.keyboardShortcut("u", modifiers: [.command])
}
// ...
}
PS: Thank you for your brainstorming ideas 😊 And sorry to the late replay. I had some issues porting the Mac Catalyst version of the app to Mac. Broken Slider and keyboardShortcut to name a few.
Hint: the following code works well on iPhone and Mac Catalyst. Try Mac.
Hint: play with step or without.
@State var inclination: Double = 0
//...
Slider(value: $inclination, in: -80...80, step: 0.01)
Button("press option+1"){ print("option+1") }.keyboardShortcut("1", modifiers: [.option])
Button("¡surprise!"){ print("¡surprise!") }.keyboardShortcut("¡", modifiers: [.option])
Short story: it will work after reboot.
It's funny I hit the same issue last week, but for a different reason. I noticed in Disk Utility, that a couple of iOS 17 disk images are mounted. So I decided to tidy-up and unmount them. The following day Xcode had no iOS support. So I installed that and it still didn't work. Restarting Xcode did not help. A reboot solved it. I would say this is a bug and poor design in Xcode. If it needs these images to be mounted, then it should mount them and not ask to download again.
The T2 chip on Intel Macs runs Bridge OS.
I'm not sure which components are required, but if you clean more than what you need, you should be able to let Xcode download what it needs and reboot. Then try to copy them from here /Library/Developer/CoreSimulator/Images/. I'm not sure if it will work. In your case the Internet speed is a factor, so do cleanup and reinstalls it overnight. It took about 10 minutes and 8 GB of my unlimited LTE data.
hdiutil info |grep image-path
image-path : /Library/Developer/CoreSimulator/Images/C1DB187D-7E6B-44D7-9ECD-A1A2BE8257B3.dmg
Good luck!
Indeed the issue appears when the parent view has onTapGesture or onLongPressGesture, and then buttons and sliders stop working. One approach is to use simultaneousGesture, where the issue is that a child view cannot prevent it from running.
In every sane framework, events propagate from child to parent, allowing the child to stop propagation. Apple being Apple think different and made it the other way around.
Example: if I want to use onTapGesture to hide the keyboard when a user taps outside a TextField, that's impossible. Why this behaviour is not the default is beyond me. The best approach for iOS 18 is simultaneousGesture with LongPressGesture, but that doesn't work on iOS 15 where a onLongPressGesture is required with a onTapGesture before it, just to keep the UI from breaking. Of course that does not work on iOS 18. On macOS a simple onTapGesture does the trick. A view modifier with conditional compilation does the trick.
Through some voodoo magic I found a way to discover if the current responder is a TextField and then I can hide it. But I can't find a way to detect if a tap is within a TextField or not.