Code block below produces different results depending on if print is commented or not:
import Combine
var cancellables = SetAnyCancellable()
enum FruitError: Error {
case bad
}
var fruit = "apple"
func getFruit() - String {
fruit
}
Just(getFruit)
//.print()
.map{$0()}
.flatMap { value - AnyPublisherString, FruitError in
print("in flat map \(value)")
if value == "apple" {
fruit = "pineapple"
return Fail(error: FruitError.bad).eraseToAnyPublisher()
}
return Just("banana").setFailureType(to: FruitError.self).eraseToAnyPublisher()
}
.retry(1)
.sink(receiveCompletion: { print($0) }, receiveValue: {print($0)})
.store(in: &cancellables)
Without print:
in flat map apple
in flat map apple
failure
With print:
in flat map apple
in flat map pineapple
banana
receive finished
finished
receive finished
Why does print or any other debug operator(breakpoint or handleEvent) change behaviour of sequence?
Playground without print - https://developer.apple.com/forums/content/attachment/d8a1d043-191b-41f3-8f0e-72dafa621374
Playground with print - https://developer.apple.com/forums/content/attachment/7c0de4c2-37fb-4136-ae8e-5ed0e77287c5
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
We have SwiftUI Alert with destructive button - "Yes, sign out"?
Alert(
title: Text("Are you sure you want to sign out?"),
message: Text("Some message"),
primaryButton: .cancel(
Text("No, don’t sign out")
),
secondaryButton: .destructive(
Text("Yes, sign out"),
action: { print("signOut") }
)
)
Button's text is displayed in pale pink but according to our design we want to change it to dark red. As an option we want change button's color as well.
How we can accomplish it?
As a side note: we found that for iOS we probably can utilise UIView.appearance(whenContainedInInstancesOf: API but it's available only on iOS but we are interested in solution for macOS
We were encourage by Frameworks Engineer reply and Apple's Official Docs and started to use this approach in our App. But next we detected that App has leaked objects when we do Memory Graph Check in UITests.
Removing of .accessibilityElement(children: .contain) solves the issue but we still want to use container identifiers in our UITests.
Here is a sample project to illustrated and reproduce the issue: https://github.com/yuri-qualtie/MemoryLeaks. All the details and steps are described in Readme
We need help with fix for .accessibilityElement(children: .contain) but any workaround is welcomed
We updated our CI machine to:
macOS Monterey Version 12.0.1
Xcode Version 13.1 (13A1030d)
We started to receive UITest failures with following error:
Testing failed:
MemoryLeaksUITests:
MemoryLeaksUITests-Runner (3507) encountered an error (The test runner failed to initialize for UI testing. If you believe this error represents a bug, please attach the result bundle at /Users/dev/Library/Developer/Xcode/DerivedData/MemoryLeaks-dduvihbyiuzwdnawggthtfwdgwks/Logs/Test/Test-MemoryLeaks-2021.11.05_13-43-58-+0300.xcresult. (Underlying Error: Timed out while enabling automation mode.))
The failure disappears if we enable UIAutomation for testmanagerd by providing password
However it's not one time action. This permission dialog still appears after some time during a day. We noticed it constantly appears after machine reboot.
Unfortunately it blocks us from using our CI machine as test runner.
There is no option(checkbox) to permanently enable(provide password) automation in this dialog. Also it's not possible to add it in Settings -> Security & Privacy -> Privacy - Automation.
Here is a sample project on GitHub to reproduce the issue.
Steps:
Reboot machine
Run in terminal
xcodebuild -target MemoryLeaksUITests -scheme MemoryLeaks test
We inspired by announce that DriverKit will come to iPadOs this fall and decided to experiment with DriverKit on macOS.
We started from scratch but followed all the recommendations from Sample.
With our installer code we can:
Install driver extension to macOS system. (systemextensionsctl list shows [activated enabled]) for our driver
See driver record using ioreg. So it's displayed: MyDriver <class IOUserService, id 0x10000193b, registered, matched, active, busy 0 (0 ms), retain 7>
See *.MyDriver process in Activity Monitor
In client code we can find a match:
private let dextIdentifier = "MyDriver"
private var lastResult: kern_return_t = kIOReturnSuccess
private var connection: io_connect_t = IO_OBJECT_NULL
var iterator: io_iterator_t = IO_OBJECT_NULL
var driver: io_service_t = IO_OBJECT_NULL
lastResult = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceNameMatching(dextIdentifier), &iterator)
print("Search for services ...")
while case let service = IOIteratorNext(iterator),
service != IO_OBJECT_NULL {
driver = service
}
IOObjectRelease(iterator)
guard driver != IO_OBJECT_NULL else { return }
So driver is not IO_OBJECT_NULL. But we stuck on IOServiceOpen. So code:
lastResult = IOServiceOpen(driver, mach_task_self_, UInt32(kIOHIDServerConnectType), &connection);
validateLastResult(forOperation: "opening service")
prints opening service: (iokit/common) general error since IOServiceOpen returns 0x2bc
What we tried:
Disable SIP in recovery mode and set systemextensionsctl developer on
Result: opening service: (iokit/common) general error
Add com.apple.developer.driverkit.userclient-access to our client App.
Result: App crashes on start and in Console we see: taskgated-helper - Unsatisfied entitlements: com.apple.developer.driverkit.userclient-access. We requested this entitlement.
We found post were com.apple.developer.driverkit.allow-any-userclient-access suggested as solution.
Result: Driver extension is not started and we see in Console:
taskgated-helper MyDriver: Unsatisfied entitlements: com.apple.developer.driverkit.allow-any-userclient-access
amfid /Library/SystemExtensions/B7624EEF-3688-4735-A58B-26FEF4DE353C/MyDriver.dext/MyDriver signature not valid: -67671
We recreated appIds, profiles on developer account that has com.apple.developer.driverkit.allow-any-userclient-access from Apple.
Result: Driver extension is started but we still see opening service: (iokit/common) general error
We modified CommunicatingBetweenADriverKitExtensionAndAClientApp.zip by setting our appIds and profiles and run in in SIP disabled mode.
Result: opening service: (iokit/common) general error
Our environment:
macOS Monterey 12.4
XCode Version 13.4 (13F17a)
Driver Code is pretty straightforward:
///// iig
class MyDriver: public IOUserClient
{
public:
virtual bool init(void) override;
virtual kern_return_t Start(IOService * provider) override;
virtual kern_return_t Stop(IOService* provider) override;
virtual void free(void) override;
};
///// cpp
#define Log(fmt, ...) os_log(OS_LOG_DEFAULT, "MyDriver - " fmt "\n", ##__VA_ARGS__)
struct MyDriver_IVars {
OSAction* callbackAction = nullptr;
};
bool MyDriver::init() {
bool result = false;
Log("init()");
result = super::init();
if (result != true)
{
Log("init() - super::init failed.");
goto Exit;
}
ivars = IONewZero(MyDriver_IVars, 1);
if (ivars == nullptr)
{
Log("init() - Failed to allocate memory for ivars.");
goto Exit;
}
Log("init() - Finished.");
return true;
Exit:
return false;
}
kern_return_t
IMPL(MyDriver, Start)
{
kern_return_t ret;
ret = Start(provider, SUPERDISPATCH);
if(ret != kIOReturnSuccess) {
Log("Start() - super::Start failed with error: 0x%08x.", ret);
goto Exit;
}
ret = RegisterService();
if (ret != kIOReturnSuccess)
{
Log("Start() - Failed to register service with error: 0x%08x.", ret);
goto Exit;
}
Log("Start() - Finished.");
ret = kIOReturnSuccess;
Exit:
return ret;
}
kern_return_t
IMPL(MyDriver, Stop)
{
kern_return_t ret = kIOReturnSuccess;
Log("Stop()");
ret = Stop(provider, SUPERDISPATCH);
if (ret != kIOReturnSuccess)
{
Log("Stop() - super::Stop failed with error: 0x%08x.", ret);
}
return ret;
}
void MyDriver::free(void)
{
Log("free()");
IOSafeDeleteNULL(ivars, MyDriver_IVars, 1);
super::free();
}
We requested com.apple.developer.driverkit.transport.usb entitlement a few days ago and it looks like it was granted since we see(can select) it at:
App Id -> Additional Capabilities Tab -> DriverKit USB Transport - Vendor ID.
We tried to choose both options at Additional Entitlements page
Default and Driver Kit and System Extension Template for **** Mac Dev. Generated profile displays DriverKit USB Transport - Vendor ID in Enabled Capabilities in browser. However downloaded profile doesn't include com.apple.developer.driverkit.transport.usb. As a result our Driver fails to start and in Console we see:
Driver: Unsatisfied entitlements: com.apple.developer.driverkit.transport.usb
/Library/SystemExtensions/675FA894-8985-4D86-B0FF-B892B9AEA27B/Driver.dext/Driver signature not valid: -67671
BTW, we tried to modify existing profile and create a new one.
Did we miss something? Is any way to check entitlement status with Apple support?
We followed WWDC Session: System Extensions and DriverKit and recreated a code to do USB device communication via IOUSBHostPipe:
struct MyDriver_IVars {
IOUSBHostInterface *interface;
IOUSBHostPipe *inPipe;
OSAction *ioCompleteCallback;
IOBufferMemoryDescriptor *inData;
uint16_t maxPacketSize;
};
kern_return_t
IMPL(MyDriver, Start)
{
...
ivars->maxPacketSize = 64;
ret = ivars->interface->CreateIOBuffer(
kIOMemoryDirectionInOut,
ivars->maxPacketSize,
&ivars->inData);
ret = CreateActionReadComplete(0, &ivars->ioCompleteCallback);
ret = ivars->inPipe->AsyncIO(ivars->inData,
ivars->maxPacketSize,
ivars->ioCompleteCallback,
0);
...
}
Our Driver is started by OS when device is connected. We see that ReadComplete callback is called:
void IMPL(MyDriver, ReadComplete)
{
Log("ReadComplete() - status - %d; bytes count - %d", status, actualByteCount);
}
However it's not obvious how to read data received in this callback. I suspect that we should use IOBufferMemoryDescriptor *inData but we didn't find any good example/sample and documentation is poor.
Our callback is called only once. It's not clear how to read a series of data from device? Should we create some loop and call inPipe->AsyncIO from callback?
Also it would be helpful to see how to pass data to device. I hope we should fill IOBufferMemoryDescriptor *inData.
According to Communicating Between a DriverKit Extension and a Client App we can use IOConnectCallScalarMethod to send/get data to Driver.
We use unchecked variation of IOConnectCallScalarMethod to call method in our Driver from Client App. In a Driver's method we set arguments->scalarOutputCount greater than 16. However in a Client app outputCount equal to 16, so we can get only a portion of output.
Is 16 limit enforced by IOConnectCallScalarMethod implementation? How we can get more than 16? Should we use IOConnectCallStructMethod instead?
We implemented communication between Swift App and DriverKit driver using IOConnectCallAsyncStructMethod. So in Swift App we have following code to setup AsyncDataCallback:
func AsyncDataCallback(refcon: UnsafeMutableRawPointer?, result: IOReturn, args: UnsafeMutablePointer<UnsafeMutableRawPointer?>?, numArgs: UInt32) -> Void {
// handle args
}
var asyncRef: [io_user_reference_t] = .init(repeating: 0, count: 8)
asyncRef[kIOAsyncCalloutFuncIndex] = unsafeBitCast(AsyncDataCallback as IOAsyncCallback, to: UInt64.self)
asyncRef[kIOAsyncCalloutRefconIndex] = unsafeBitCast(self, to: UInt64.self)
......
let notificationPort = IONotificationPortCreate(kIOMasterPortDefault)
let machNotificationPort = IONotificationPortGetMachPort(notificationPort)
let runLoopSource = IONotificationPortGetRunLoopSource(notificationPort)!
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource.takeUnretainedValue(), CFRunLoopMode.defaultMode)
var input = "someinput".map { UInt8($0.asciiValue!) }
let inputSize = input.count
IOConnectCallAsyncStructMethod(
connection,
123,
machNotificationPort,
&asyncRef,
UInt32(kIOAsyncCalloutCount),
&input,
inputSize,
nil,
nil
)
In the driver's ExternalMethod we save callback in ivars:
ivars->callbackAction = arguments->completion;
ivars->callbackAction->retain();
Next we start communication with our device in a separate thread and execute callback when we get data from device:
SendDataAsync(void *data, uint32_t dataLength) {
const int asyncDataCount = 16;
if (ivars->callbackAction != nullptr) {
Log("SendDataAsync() - got %u bytes", dataLength);
uint64_t asyncData[asyncDataCount] = { };
asyncData[0] = dataLength;
memcpy(asyncData + 1, data, dataLength);
AsyncCompletion(ivars->callbackAction, kIOReturnSuccess, asyncData, asyncDataCount);
}
Limitation 1:
Our device produces data packet every 10 ms. So driver gets 100 data packets per second. Receive rate is good and we verified it by logs. However we see some delay in AsyncCallback in Swift App. It looks like async calls are queued since we see that Swift App gets callbacks for a few seconds when we stopped to send data from Driver. We measured receive rate in Swift App and it is about 50 data packets per second.
So what's a minimum call rate for AsyncCompletion? Is it higher than 10 ms?
Maybe there is other more efficient way to asynchronously pass data from Driver to Swift App?
Limitation 2:
We thought we can buffer data packets and decrease AsyncCompletion call rate. However asyncData could be only 16 of uint64_t by declaration typedef uint64_t IOUserClientAsyncArgumentsArray[16];. Size of our data packer is 112 bytes that perfectly fits to max args size(8*16 = 128 bytes). So we can't cache and send 2 data packets.
How we can avoid this limitation and send more data via AsyncCompletion?
Is there any other API for asynchronous communication that allows send more data back?
We use .xcresult files on our CI and recently noticed that size of file significantly increased. So previously we had files ~ 50 MB but now they are ~ 300 MB.
After investigation of .xcresult contents we found that it contains macOS Logs - test-session-systemlogs-2022.01.05_13-13-07-+0000
In testmanagerd .log we see in a last line:
Moved logarchive from /var/tmp/test-session-systemlogs-2022.01.05_13-13-07-+0000.logarchive to ../Staging/1_Test/Diagnostics/My Mac_4203018E-580F-C1B5-9525-B745CECA79EB/test-session-systemlogs-2022.01.05_13-13-07-+0000.logarchive
Issue is reproducible on a new project.
Steps:
File -> New -> Project
Select macOS -> App
Enable include test
For simplicity disable(comment) all the UITests except ResultSampleUITests::testExample
Add XCTAssertTrue(false) after app.launch()
Run tests from console and specify path to resultBundlePath
xcodebuild -project ResultSample.xcodeproj -scheme ResultSample -resultBundlePath ~/Downloads/2/all-tests -test-timeouts-enabled YES test
7. When tests are finished navigate to resultBundlePath and check size of all-tests.xcresult.
It has size 51.6 MB for me.
If change XCTAssertTrue(false) to XCTAssertTrue(true) then size of all-tests.xcresult is decreased to 31 KB.
Any idea how to disable/delete macOS diagnostic logs or decrease a size of .xcresult
We are developing driver for our USB device. We've implemented commutation using IOUSBHostPipe::IO and it perfectly works for data packets that less than 256 bytes. However it hangs when reply from USB device is about 512 bytes. We see 0x2ed // device not responding error when we unplug our device and driver is stopped.
Here is our code for setup:
constexpr uint32_t kOutEndpointAddress = 1;
constexpr uint32_t kInEndpointAddress = 129;
constexpr uint16_t kBufferSize = 256;
.....
struct ForcePlateDriver_IVars {
....
IOUSBHostPipe *inPipe;
IOBufferMemoryDescriptor *inData;
uint16_t maxPacketSize;
};
.....
ret = ivars->interface->CopyPipe(kInEndpointAddress, &ivars->inPipe);
ret = ivars->interface->CreateIOBuffer(kIOMemoryDirectionIn,
ivars->maxPacketSize,
&ivars->inData);
We use following code for reading data from USB device:
uint32_t bytesTransferred = 0;
ret = ivars->inPipe->IO(
ivars->inData,
ivars->maxPacketSize,
&bytesTransferred,
0);
What we tried:
Increase kBufferSize to 512 but drive still hangs
Change 0 to 2000 (timeout) for inPipe->IO method.
Result method returns - 0x2d6(// I/O Timeout)
We are developing our Driver using DriverKit. In client App we successfully discover our driver but can't get IORegistry properties except IOClass. So in a client App we use following code to read properties:
private func debugRegistry(device: io_object_t) {
var dictionary: Unmanaged<CFMutableDictionary>?
IORegistryEntryCreateCFProperties(device, &dictionary, kCFAllocatorDefault, .zero)
if let dictionary = dictionary {
let values = dictionary.takeUnretainedValue()
print(values)
}
}
output is:
{
IOClass = IOUserService;
}
We tested same code on macOS and output contains about 20+ properties. It looks like IOKi doesn't allow to read other properties except IOClass.
Environment:
Xcode - Version 14.1 beta 2 (14B5024i).
iPadOS - iOS 16.1 (20B5050f)
We created Driver sample by Xcode template and following macro was added into code:
#define Log(fmt, ...) os_log(OS_LOG_DEFAULT, "Driver - " fmt "\n", ##__VA_ARGS__)
We used this macro in init and start. For example:
bool ForcePlateDriver::init() {
Log("init()");
But our logs are not displayed in Console app.
Did we miss something? Is anything else is required to have logs for Driver?
Our environment:
MacOS Monterey - 12.4 (21F79)
Xcode - Version 13.4 (13F17a)
We used Locale::usesMetricSystem to distinguish between metric and Imperial(US) measurement systems. We set "-AppleLocale en_US" as launch argument for App in UITests but usesMetricSystem still returns true in case user's locale are not equal to "US" in System Preferences - Language and Region - Region.
Here is a demo project to illustrate the issue: https://github.com/yuri-qualtie/UseMetricSystemDemo
Precondition: Change user region to not US(for example Australia) in System Preferences - Language and Region - Region
We expect that code:
print(Locale.current.usesMetricSystem)
prints false when -AppleLocale en_US is set but actual result is true
Probably there is alternative way how to change measurement system via launch arguments or App's settings in Xcode?
We got development entitlement for our Driver that we requested here: https://developer.apple.com/contact/request/system-extension/
Next we tested our Driver on test devices and now want to upload build into TestFlight.
But it looks like we need distribution version of same entitlements.
Where we can request them?
BTW, Apple Docs: Requesting Entitlements for DriverKit Development describe only development approach. It would be good to add instructions for Distribution as well.