I’m implementing Apple Sign In in React Native using this library:
https://github.com/invertase/react-native-apple-authentication
And there’s a handler for the onPress event of the Apple Sign-In button given like so:
import { appleAuth } from '#invertase/react-native-apple-authentication';
async function onAppleButtonPress() {
// performs login request
const appleAuthRequestResponse = await appleAuth.performRequest({
requestedOperation: appleAuth.Operation.LOGIN,
requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
});
// get current authentication state for user
// /!\ This method must be tested on a real device. On the iOS simulator it always throws an error.
const credentialState = await appleAuth.getCredentialStateForUser(appleAuthRequestResponse.user);
// use credentialState response to ensure the user is authenticated
if (credentialState === appleAuth.State.AUTHORIZED) {
// user is authenticated
}
}
However, when I convert this to clojurescript like so:
(reg-fx
:apple-signin-fx
(fn [navigation]
(go (let [appleAuthRequestResponse
(<p! (.performRequest appleAuth
(clj->js
{:requestedOperation (.. appleAuth -Operation -LOGIN)
:requestedScopes [(.. appleAuth -Scope -Email)
(.. appleAuth -Scope -FULL_NAME)]})))]))))
I’m getting the following error:
JSON value '{
nonceEnabled = 1;
requestedOperation = 1;
requestedScopes = (
"<null>",
1
);
}' of type NSMutableDictionary cannot be converted to ASAuthorizationAppleIDRequest *
+[RCTConvert(ASAuthorizationAppleIDRequest) ASAuthorizationAppleIDRequest:]
RCTConvert+ASAuthorizationAppleIDRequest.m:85
__41-[RCTModuleMethod processMethodSignature]_block_invoke_16
-[RCTModuleMethod invokeWithBridge:module:arguments:]
facebook::react::invokeInner(RCTBridge*, RCTModuleData*, unsigned int, folly::dynamic const&)
facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int)::$_0::operator()() const
invocation function for block in facebook::react::RCTNativeModule::invoke(unsigned int, folly::dynamic&&, int)
_dispatch_call_block_and_release
_dispatch_client_callout
_dispatch_main_queue_callback_4CF
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__
__CFRunLoopRun
CFRunLoopRunSpecific
GSEventRunModal
-[UIApplication _run]
UIApplicationMain
main
start
How to fix this?
Related
I am new to Arduino and working on a project to pass cryptographic keys between Arduino (ESP8266) and a React Native app. On the ESP8266 side I am using arduino crypto library and for React Native I am using react-native-crypto-js. The encryption doesn't seem to do the right thing and returns garbage. So, as a first step I was trying to pass the key from Arduino into the mobile app (using the bluetooth HC-05). The following code was used in the arduino side:
void getConnected() {
// wait till someone try to connect to the user
if (btSerial.available() > 0) {
String message = btSerial.readString();
if(message == "Hello") {
Serial.println("user trying to connect");
byte key[32];
device.getKey(key);
Serial.println((char*)key);
btSerial.write((char*)key);
}
}
}
The key is generated using RNG.rand(key, sizeof(key)) and I also printed the generated bytes separately and it is something like:
137 224 186 115 0 0 0 0 172 228 254 63 131 53 32 64 208 218 255 63 13 0 0 0 172 228 254 63 48 70 32 64
As you see above, since there are 0s in the bytes, the code in the React Native app is only getting the first 4 bytes, and the remaining is ignored as it is thinking the 5th byte to be the end of string.
The code used in the App is as below:
async setup(deviceId) {
console.log('connecting');
await BluetoothSerial.connect(deviceId);
console.log('connected');
await BluetoothSerial.write('Hello');
setTimeout(async () => {
let key = await BluetoothSerial.readFromDevice();
console.log(key);
}, 3000);
// const input = await BluetoothSerial.readFromDevice();
return true;
}
I would really appreciate some pointers. Please help.
Thanks
Works perfectly in iOS 10. After I updated my iOS to iOS11 the application is crashing while saving data to core data with an exception.
I have used RZVinyl framework for coredata
BOOL isSaved = [currentContext save:&saveErr];
Assertion failed: (moreParameters->mostRecentEntry ==
CFArrayGetValueAtIndex(stack, stackCount - 1)), function
NSKeyValuePopPendingNotificationPerThread, file
/BuildRoot/Library/Caches/com.apple.xbs/Sources/Foundation_Sim/Foundation-1444.12/EO.subproj/NSKeyValueObserving.m, line 933.
0 libsystem_kernel.dylib 0x00000001826fd348 __pthread_kill + 8
1 libsystem_pthread.dylib 0x0000000182811354 pthread_kill$VARIANT$mp + 396
2 libsystem_c.dylib 0x000000018266cfd8 abort + 140
3 libsystem_c.dylib 0x0000000182640abc basename_r + 0
4 Foundation 0x00000001834f1a9c -[NSRunLoop+ 178844 (NSRunLoop) runUntilDate:] + 0
5 Foundation 0x00000001834df538 NSKeyValueDidChange + 436
6 Foundation 0x0000000183597ae4 NSKeyValueDidChangeWithPerThreadPendingNotifications + 140
7 CoreData 0x00000001854107c8 -[NSManagedObject didChangeValueForKey:] + 120
8 CoreData 0x0000000185416358 -[NSManagedObject+ 844632 (_NSInternalMethods) _updateFromRefreshSnapshot:includingTransients:] + 692
9 CoreData 0x000000018542e054 -[NSManagedObjectContext+ 942164 (_NestedContextSupport) _copyChildObject:toParentObject:fromChildContext:] + 652
10 CoreData 0x000000018542e4bc -[NSManagedObjectContext+ 943292 (_NestedContextSupport) _parentProcessSaveRequest:inContext:error:] + 804
11 CoreData 0x000000018542f3f0 __82-[NSManagedObjectContext+ 947184 (_NestedContextSupport) executeRequest:withContext:error:]_block_invoke + 580
12 CoreData 0x0000000185431644 internalBlockToNSManagedObjectContextPerform + 92
13 libdispatch.dylib 0x0000000182569048 _dispatch_client_callout + 16
14 libdispatch.dylib 0x0000000182571ae8 _dispatch_queue_barrier_sync_invoke_and_complete + 56
15 CoreData 0x000000018541dd10 _perform + 232
16 CoreData 0x000000018542f0e4 -[NSManagedObjectContext+ 946404 (_NestedContextSupport) executeRequest:withContext:error:] + 172
17 CoreData 0x0000000185387ff8 -[NSManagedObjectContext save:] + 2580
NSManagedObjectContext *currentContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[[currentContext userInfo] setObject:self forKey:kRZCoreDataStackParentStackKey];
[self performBlock:^{
BOOL hasChanges = [currentContext hasChanges];
if ( !hasChanges) {
RZVLogInfo(#"Managed object context %# does not have changes, not saving", self);
rzv_performSaveCompletionAsync(completion, nil);
return;
}
NSError *saveErr = nil;
BOOL isSaved = [currentContext save:&saveErr];
if ( !isSaved) {
RZVLogError(#"Error saving managed object context context %#: %#", self, saveErr);
rzv_performSaveCompletionAsync(completion, saveErr);
}
}];
Had the same thing right now and was looking for an answer when I came across your question.
Without any answers to be found I did some in-depth investigation and found the cause (at least in my case).
It turned out that one of the object's relationships was observing KV changes to update the object regarding changes to it's values, and it was also updating a change to the value of the relationship.
That triggered and update on the Object, which caused the relationship to updated with a change, and so on and so forth...
This recursion in KVO caused a crash.
Make sure that if you are observing changes via willChangeValue and didChangeValue to update your relationship regarding this change, don't update if the observer is the one being set.
Does that make sense for you?
Let me know if this is the case and you need a code sample to understand this very confusing answer.
UPDATE:
I know my answer is quite confusing and vague, so I'll add an example.
Consider the following.
We have two example classes which has relationship to each other (i.e reverse relationship):
class A: NSManagedObject {
#NSManaged var id: NSNumber!
#NSManaged var title: String?
#NSManaged var b: B!
override func willChangeValue(forKey key: String) {
super.willChangeValue(forKey: key)
b?.willChangeValue(forKey: "a")
}
override func didChangeValue(forKey key: String) {
super.didChangeValue(forKey: key)
b?.didChangeValue(forKey: "a")
}
}
class B: NSManagedObject {
#NSManaged var id: NSNumber!
#NSManaged var name: String?
#NSManaged var date: Date?
#NSManaged var a: A!
override func willChangeValue(forKey key: String) {
super.willChangeValue(forKey: key)
a?.willChangeValue(forKey: "b")
}
override func didChangeValue(forKey key: String) {
super.didChangeValue(forKey: key)
a?.didChangeValue(forKey: "b")
}
func setNewA(_ newA: A) {
newA.b = self
a = newA
}
}
We use willChangeValue and didChangeValue in each class to notify it's relationship regarding changes in itself.
Now consider the following code:
let b = B(context: context)
let a = A(context: context)
b.setNewA(a)
We use the setNewA function to set the reverse reference.
In the function, first b assigns itself to a.b for the reverse reference and then sets self.a reference.
At this point, a already knows about b.
The later will cause willChangeValue and didChangeValue on b to be called (as we set a). Then a will pick up the update and notify b.
From here on, try can guess how it continues.
This was pretty much what happened to me, with a few minor differences.
I overrode these functions because I am using a NSFetchedResultsController and I needed to pick up on changes in the relationships to update my UI.
It threw me in a loop that caused the crash.
At the end, the fix was rather simple. A was modified to be:
override func willChangeValue(forKey key: String) {
super.willChangeValue(forKey: key)
guard key != "b" else { return }
b?.willChangeValue(forKey: "a")
}
override func didChangeValue(forKey key: String) {
super.didChangeValue(forKey: key)
guard key != "b" else { return }
b?.didChangeValue(forKey: "a")
}
and B was modified the same way, to be:
override func willChangeValue(forKey key: String) {
super.willChangeValue(forKey: key)
guard key != "a" else { return }
a?.willChangeValue(forKey: "b")
}
override func didChangeValue(forKey key: String) {
super.didChangeValue(forKey: key)
guard key != "a" else { return }
a?.didChangeValue(forKey: "b")
}
This prevents each from updating the other once the relationship itself is set (which is redundant, as each is already notified once one of it's properties is set), thus breaking the cycle.
Again, this was the case on my end and this is what fixed it.
Don't know if you're experiencing the issue due to the same reason, but hopefully it'll give you an idea where to look.
Hope it's easier to understand now.
If you're still having trouble understanding, share some code or contact me directly and I'll try and help.
Fabric Crashlytics is crashing on calling CLSLogv method occasionally. The crash is very random, not sure on what input it's crashing.
Here is the crash log:
Crashed: com.apple.main-thread
0 CoreFoundation 0x18289d688 __CFStringAppendFormatCore + 12780
1 CoreFoundation 0x18289a464 _CFStringCreateWithFormatAndArgumentsAux2 + 244
2 Foundation 0x1831b6320 -[NSPlaceholderString initWithFormat:locale:arguments:] + 168
3 Dream11 0x1004823e4 CLSLogv (CLSUserLogging.m:368)
4 Dream11 0x1001d73a8 specialized crashlyticsLog(format : String, [CVarArg], file : String, function : String, line : Int) -> () (LogManager.swift)`
Here is the method.
func VERBOSELOG(_ format: String = "",
_ args:[CVarArg] = [],
file: String = #file,
function: String = #function,
line: Int = #line) {
if ENABLED_LOGGING.contains("VERBOSE") {
do {
try crashlyticsLog(format: "\nVERBOSE: " + format, args, file: file, function: function, line: line)
} catch let error {
print(error)
}
}
}
func crashlyticsLog(format: String = "",
_ args:[CVarArg] = [],
file: String = #file,
function: String = #function,
line: Int = #line) throws {
let filename = file.components(separatedBy: "/").last!.components(separatedBy: ".").first!
#if SWIFT_DEBUG
print("\(filename).\(function) line \(line) $ \(format)")
#else
CLSLogv("\(filename).\(function) line \(line) $ \(format)", getVaList(args))
#endif
}
I faced a similar crash, that happened randomly with following stack trace
0 CoreFoundation 0x1b99b84d4 __CFStringAppendFormatCore + 6000
1 CoreFoundation 0x1b99ba5bc _CFStringCreateWithFormatAndArgumentsAux2 + 136
2 flockmail 0x1006725ec CLSLogv + 374 (CLSUserLogging.m:374)
The problem that I later figured out was the way I was logging messages.
CLSLogv(message, getVaList([])) // Incorrect
I was passing message in the format, so if the message had some %#'s or %d's or %0 or similar stuff, then it would look for vaList to replace it.
Fix was
CLSLogv("%#", getVaList([message]))
In you case, it seems format is supplied from outside, just make sure the format string parameter is in sync with args parameter.
Further references :
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Strings/Articles/FormatStrings.html
https://docs.fabric.io/apple/crashlytics/enhanced-reports.html#custom-logs
Is it the character limit of NSLog, I had the same crash for NSLog and CLSLogv. Not for print
I have a project in which I am using both objective-c and swift, not sure if this is relevant but might be.
I have a class defined as follows:
#objc public class BHCloudFileManager {
...
}
This class is a singleton and so has a property:
public class var sharedManager: BHCloudFileManager {
struct Singleton {
static let instance = BHCloudFileManager()
}
return Singleton.instance
}
And also declares an instance variable as such:
var cloudFilesAwaitingUpload: [BHCloudFile] = [] // crash happens on this line
It might be worth mentioning that BHCloudFile is an objective-c class whereas BHCloudFileManager is clearly a swift class. The sharedManager method is first called on launch from objective-c code.
Prior to my updating my Mac to Yosemite (there may have also been an Xcode upgrade but I'm not sure) this code all worked fine, but now I get a crash on the property initialisation line. My init() method appends to this array, but that shouldn't be an issue, should it?
If you have any idea what might be causing this it would be greatly appreciated, I'm at a bit of a loose end!
Platform:
Occurs on iOS 7.1 on an iPad 3rd gen. Does not occur on iOS 8.1 in the simulator.
Exception:
Thread 1: EXC_BREAKPOINT (code=EXC_ARM_BREAKPOINT, subcode=0xe7ffdefe)
Stack trace:
0 0x2bec10c4 in dyld_fatal_error ()
1 0x2bec1f06 in dyld::halt(char const*) ()
2 0x2bec369e in dyld::fastBindLazySymbol(ImageLoader**, unsigned long) ()
3 0x3b0e40d0 in dyld_stub_binder ()
4 0x0005346c in Sparkjar.BHCloudFileManager.init (Sparkjar.BHCloudFileManager.Type)() -> Sparkjar.BHCloudFileManager at /Users/georgegreen/Code/BeeHive/BeeHive/BeeHive/models/BHCloudFileManager.swift:22
5 0x00053328 in Sparkjar.BHCloudFileManager.__allocating_init (Sparkjar.BHCloudFileManager.Type)() -> Sparkjar.BHCloudFileManager ()
6 0x000532e8 in globalinit_func1 at /Users/georgegreen/Code/BeeHive/BeeHive/BeeHive/models/BHCloudFileManager.swift:30
7 0x0185902a in __swift_once_block_invoke ()
8 0x3b0bf81e in _dispatch_client_callout ()
9 0x3b0c760e in dispatch_once_f$VARIANT$mp ()
10 0x01859016 in swift_once ()
11 0x0005d4c0 in Sparkjar.BHCloudFileManager.(sharedManager.getter : Sparkjar.BHCloudFileManager).(Singleton #1).instance.mutableAddressor : Sparkjar.BHCloudFileManager at /Users/georgegreen/Code/BeeHive/BeeHive/BeeHive/models/BHCloudFileManager.swift:30
12 0x000532b8 in Sparkjar.BHCloudFileManager.sharedManager.getter : Sparkjar.BHCloudFileManager at /Users/georgegreen/Code/BeeHive/BeeHive/BeeHive/models/BHCloudFileManager.swift:32
13 0x000533b0 in #objc Sparkjar.BHCloudFileManager.sharedManager.getter : Sparkjar.BHCloudFileManager ()
14 0x00170570 in -[BHAppDelegate setupApplication] at /Users/georgegreen/Code/BeeHive/BeeHive/BeeHive/BHAppDelegate.m:54
15 0x00170414 in -[BHAppDelegate application:didFinishLaunchingWithOptions:] at /Users/georgegreen/Code/BeeHive/BeeHive/BeeHive/BHAppDelegate.m:41
16 0x327b95a6 in -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] ()
17 0x327b8efa in -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] ()
18 0x327b358a in -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] ()
19 0x3274f708 in -[UIApplication handleEvent:withNewEvent:] ()
20 0x3274e870 in -[UIApplication sendEvent:] ()
21 0x327b2cc8 in _UIApplicationHandleEvent ()
22 0x34d95aec in _PurpleEventCallback ()
23 0x34d956d6 in PurpleEventCallback ()
24 0x2fef8ab6 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
25 0x2fef8a52 in __CFRunLoopDoSource1 ()
26 0x2fef7226 in __CFRunLoopRun ()
27 0x2fe61f4e in CFRunLoopRunSpecific ()
28 0x2fe61d32 in CFRunLoopRunInMode ()
29 0x327b1ef0 in -[UIApplication _run] ()
30 0x327ad16c in UIApplicationMain ()
31 0x001ab948 in main at /Users/georgegreen/Code/BeeHive/BeeHive/BeeHive/main.m:16
I have a method that is similar to the tee utility. It receives a notification that data has been read on a pipe, and then writes that data to one or more pipes (connected to subordinate applications). If a subordinate app crashes, then that pipe is broken, and I naturally get an exception, which is then handled in a #try...#catch block.
This works most of the time. What I'm puzzled by is that occasionally, the exception crashes the app entirely with an uncaught exception, and pointing to the writeData line . I haven't been able to figure out what the pattern is on when it crashes, but why should it ever NOT be caught? (Note this is not executing inside the debugger.)
Here's the code:
//in setup:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(tee:) name:NSFileHandleReadCompletionNotification object:fileHandle];
-(void)tee:(NSNotification *)notification
{
// NSLog(#"Got read for tee ");
NSData *readData = notification.userInfo[NSFileHandleNotificationDataItem];
totalDataRead += readData.length;
// NSLog(#"Total Data Read %ld",totalDataRead);
NSArray *pipes = [teeBranches objectForKey:notification.object];
if (readData.length) {
for (NSPipe *pipe in pipes {
#try {
[[pipe fileHandleForWriting] writeData:readData];
}
#catch (NSException *exception) {
NSLog(#"download write fileHandleForWriting fail: %#", exception.reason);
if (!_download.isCanceled) {
[_download rescheduleOnMain];
NSLog(#"Rescheduling");
}
return;
}
#finally {
}
}
}
I should mention that I have set a signal handler in my AppDelegate>appDidFinishLaunching:
signal(SIGPIPE, &signalHandler);
signal(SIGABRT, &signalHandler );
void signalHandler(int signal)
{
NSLog(#"Got signal %d",signal);
}
And that does execute whether the app crashes or the signal is caught.
Here's a sample crash backtrace:
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Application Specific Information:
*** Terminating app due to uncaught exception 'NSFileHandleOperationException', reason: '*** -[NSConcreteFileHandle writeData:]: Broken pipe'
abort() called
terminating with uncaught exception of type NSException
Application Specific Backtrace 1:
0 CoreFoundation 0x00007fff838cbbec __exceptionPreprocess + 172
1 libobjc.A.dylib 0x00007fff90e046de objc_exception_throw + 43
2 CoreFoundation 0x00007fff838cba9d +[NSException raise:format:] + 205
3 Foundation 0x00007fff90a2be3c __34-[NSConcreteFileHandle writeData:]_block_invoke + 81
4 Foundation 0x00007fff90c53c17 __49-[_NSDispatchData enumerateByteRangesUsingBlock:]_block_invoke + 32
5 libdispatch.dylib 0x00007fff90fdfb76 _dispatch_client_callout3 + 9
6 libdispatch.dylib 0x00007fff90fdfafa _dispatch_data_apply + 110
7 libdispatch.dylib 0x00007fff90fe9e73 dispatch_data_apply + 31
8 Foundation 0x00007fff90c53bf0 -[_NSDispatchData enumerateByteRangesUsingBlock:] + 83
9 Foundation 0x00007fff90a2bde0 -[NSConcreteFileHandle writeData:] + 150
10 myApp 0x000000010926473e -[MTTaskChain tee:] + 2030
11 CoreFoundation 0x00007fff838880dc __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
12 CoreFoundation 0x00007fff83779634 _CFXNotificationPost + 3140
13 Foundation 0x00007fff909bb9b1 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
14 Foundation 0x00007fff90aaf8e6 _performFileHandleSource + 1622
15 CoreFoundation 0x00007fff837e9ae1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
16 CoreFoundation 0x00007fff837dbd3c __CFRunLoopDoSources0 + 476
17 CoreFoundation 0x00007fff837db29f __CFRunLoopRun + 927
18 CoreFoundation 0x00007fff837dacb8 CFRunLoopRunSpecific + 296
19 HIToolbox 0x00007fff90664dbf RunCurrentEventLoopInMode + 235
20 HIToolbox 0x00007fff90664b3a ReceiveNextEventCommon + 431
21 HIToolbox 0x00007fff9066497b _BlockUntilNextEventMatchingListInModeWithFilter + 71
22 AppKit 0x00007fff8acf5cf5 _DPSNextEvent + 1000
23 AppKit 0x00007fff8acf5480 -[NSApplication nextEventMatchingMask:untilDate:inMode:dequeue:] + 194
24 AppKit 0x00007fff8ace9433 -[NSApplication run] + 594
25 AppKit 0x00007fff8acd4834 NSApplicationMain + 1832
26 myApp 0x00000001091b16a2 main + 34
27 myApp 0x00000001091ab864 start + 52
So, the nice folks at Crashlytics were able to help me here. To quote them:
Here's the story:
The pipe dies because the child process crashes. The very next read/write will cause a fault.
That write occurs, which results in a SIGPIPE (not a runtime exception).
If that SIGPIPE is masked/ignored, NSFileHandle checks errno and creates a runtime exception which it throws.
A function deeper than your tee: method has wrapped this write in a #try/#catch (proved by setting a breakpoint on __cxa_begin_catch)
That function, which turns out to be "_dispatch_client_callout", which makes a call to objc_terminate, which effectively kills the
process.
Why does _dispatch_client_callout do this? I'm not sure, but you can
see the code here:
http://www.opensource.apple.com/source/libdispatch/libdispatch-228.23/src/object.m
Unfortunately, AppKit has a really poor track record of being a good
citizen in the face of runtime exceptions.
So, you are right that NSFileHandle raises a runtime exception about
the pipe dying, but not before a signal is raised that kills the
process. Others have encountered this exact issue (on iOS, which has
much better semantics about runtime exceptions).
How can I catch EPIPE in my NSFIleHandle handling?
In short, I don't believe it is possible for you to catch this
exception. But, by ignoring SIGPIPE and using lower-level APIs to
read/write to this file handle, I believe you can work around this. As
a general rule, I'd recommend against ignoring signals, but in this
case, it seems reasonable.
Thus the revised code is now:
-(void)tee:(NSNotification *)notification {
NSData *readData = notification.userInfo[NSFileHandleNotificationDataItem];
totalDataRead += readData.length;
// NSLog(#"Total Data Read %ld",totalDataRead);
NSArray *pipes = [teeBranches objectForKey:notification.object];
if (readData.length) {
for (NSPipe *pipe in pipes ) {
NSInteger numTries = 3;
size_t bytesLeft = readData.length;
while (bytesLeft > 0 && numTries > 0 ) {
ssize_t amountSent= write ([[pipe fileHandleForWriting] fileDescriptor], [readData bytes]+readData.length-bytesLeft, bytesLeft);
if (amountSent < 0) {
NSLog(#"write fail; tried %lu bytes; error: %zd", bytesLeft, amountSent);
break;
} else {
bytesLeft = bytesLeft- amountSent;
if (bytesLeft > 0) {
NSLog(#"pipe full, retrying; tried %lu bytes; wrote %zd", (unsigned long)[readData length], amountSent);
sleep(1); //probably too long, but this is quite rare
numTries--;
}
}
}
if (bytesLeft >0) {
if (numTries == 0) {
NSLog(#"Write Fail4: couldn't write to pipe after three tries; giving up");
}
[self rescheduleOnMain];
}
}
}
}
I know this doesn't do much to answer why the exception catching seems broken, but I hope that this is a helpful answer to workaround the issue.
I faced a similar issue trying to read/write to a socket wrapped in an NSFileHandle. I worked around it by testing the pipe availability directly with the fileDescriptor like so
- (BOOL)socketIsValid
{
return (write([fh fileDescriptor], NULL, 0) == 0);
}
then I tested with that method before attempting to call writeData:.