There is a piece of code that does DNS lookups using CFHostStartInfoResolution(). However this is synchronously and thus blocks anything before it returns - it's bad and I also think it causes crashes due to timeouts when connection is weak (when its bad it fails out safely directly)
So I want to do this asynchronously, as it's supposed to in the docs https://developer.apple.com/library/ios/documentation/CoreFoundation/Reference/CFHostRef/Reference/reference.html
New docs URL 20190227: https://developer.apple.com/documentation/cfnetwork/cfhostref
Specifically it says:
If you want to resolve the host asynchronously. call CFHostSetClient
to associate your client context and user-defined callback function
with the host. Then call CFHostScheduleWithRunLoop to schedule the
host on a run loop.
However this put me off because I haven't coded C in ages and can't get callbacks and runloops/threading right.
How am I supposed to call CFHostSetClient, CFHostScheduleWithRunLoop, and how do I implement those callbacks? Do I need to start a new thread?
Actually CFHost has a bug since on macOS since 10.7. Up to 10.7 it was possible to cancel a synchronous lookup calling CFHostCancelInfoResolution() on a second thread but since 10.7 this is not possible any longer (it just won't cancel the lookup). I reported that to Apple in 2013 (bug number is 13672880) but despite confirming it, Apple has never fixed it up to today.
Yet the more interesting part was what Apple suggested in their reply:
The best API for host name resolution is DNSServiceGetAddrInfo
and that's asynchronous and cancelable.
This API is documented to exist on macOS since 10.11.4, on iOS since 9.3, on tvOS since 9.2 and on watchOS since 2.2 - yet I think this cannot be correct, it must have existed, otherwise how could Apple recommend it in 2013 (10.11 was released 2015). I can confirm that this API also existed on iOS 8 and on macOS 10.9 and probably even earlier on both systems.
This API is internally using an undocumented asynchronous version of the otherwise synchronous C call getaddrinfo() which is found on all POSIX like systems today.
One advantage over other APIs is that you can choose if you only want to retrieve IPv4, IPv6, or both kind of addresses or you can let the system decide to pick the address family for you, depending on which addresses the system considers reachable at the moment (this is the default for most other resolving APIs).
Also in case a system has multiple active network interfaces (e.g. cable + WiFi or WiFi + mobile), you can pick the interface to use as different DNS settings may be set on different interfaces (and different DNS servers can deliver different results for the same domain name). If you don't pick one, the system will always use the current default server (this is the default for most other resolving APIs).
Should be something like this
CFHostSetClient(host, callbackFunction, hostContext);
CFHostScheduleWithRunLoop(host, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
CFHostStartInfoResolution(host, kCFHostAddresses, 0);
And callbackFunction
void callbackFunction(CFHostRef theHost, CFHostInfoType typeInfo, const CFStreamError *error, void *info) {
// Do something
}
You don't need to start a new thread, system will do it for you.
Related
The Apple docs mark CFStreamCreatePairWithSocket as deprecated since IOS 15.0.
What would be a related successor ?
We use CFSocket/NSStream functions currently to have event driven network reads/writes in a runloop.
For the record, we ended up rewriting our code to use plain Berkeley sockets together with the GCD dispatch_source machinery ... there is a working socket server sample not triggering the local network prompt at
https://github.com/leopatras/GCDSimpleSocketServer/
The dispatch_source_zzz functions allow a similar event driven approach like the CFStreamCreatePairWithSocket function (and even less code).
See https://github.com/leopatras/cfsocket for comparison with the old CFSocket stuff.
As this is anyway deprecated and triggers the local network prompt in some situations: don't use it anymore.
I had an intensive exchange with the Apple support about this topic, they did recommend using the new Network framework functions instead of Berkeley sockets (See https://developer.apple.com/documentation/network?language=objc) and I tried hard to use them however I failed to create a simple reliable working echo server with those functions in obj-C (didn't try the Swift route).
I'm porting an Android device's VPN App to iOS (using NEPacketTunnelProvider).
Android provides a mechanism to bypass VPN for some tcp/udp connections, using the following API:
class VpnService {
// ...
public boolean protect(int socket) { /* ... */ }
I don't see equivalent API in iOS. How do I implement something equivalent for iOS?
Coming from Android and knowing nothing of Apple API (except Swift and ObjC++ languages), I will try to point out what a normal developer would like to know.
An iOS App's life ends the moment the views are closed, hence a permanent VPN-Service is ONLY possible in an extension, which is a completely different target than that of your views (because iOS has no Service concept).
In addition to knowing above, learn the fact that any connection (aka Socket) created from within your extension is magically excluded (aka protected) from going through packetFlow (aka Tunnel), no matter if it's a Raw-socket made by C/C++ or OOP-Wrapped class in Swift5.
Surprisingly enough, actually making your extension's socket go through tunnel is much harder,
and you would need to use NEPacketTunnelProvider class's methods:
- createTCPConnectionThroughTunnelToEndpoint:enableTLS:TLSParameters:delegate:
- createUDPSessionThroughTunnelToEndpoint:fromEndpoint:
Note that above are instance methods, which is what minus sign in ObjC means,
so only available in extension context (but there is no escaping from the tunnel for App-targets anyway).
See also: https://developer.apple.com/forums/thread/94430
This is for a visualisation project on what data gets recorded about us from our phones.
The idea would be to log as much detail as is reasonable to an internal location (probably) on the phone for later analysis, e.g. HTTP requests. It doesn’t need to be secret at all – the subject will be aware they are participating – and it doesn’t have to be 100% automatic; if the phone owner needs to perform some action regularly that’s okay too, although they need to be able to use their phone approximately normally throughout the day.
I can’t find any Apple APIs that look suitable, but that’s hardly surprising. I can find some approaches that would potentially work on OSX (tcpdump, netstat), so perhaps a jailbroken iOS device would support one of those?
Alternatively, running a custom proxy server would open up a bunch more options, but is there any way to get a mobile device to reliably route through a proxy server?
It appears this question provides a viable proxy-server-based approach:
https://apple.stackexchange.com/questions/81102/proxy-settings-for-iphone-3g-connection
Basically, it seems it is possible to route all requests through a proxy server, even over cellular.
I'm trying to save a high score in my spritekit game. Based on all the tutorials I've watched and the stack overflow answers i've read, the following code should work:
NSUserDefaults.standardUserDefaults().setInteger(highScore, forKey: "highScore")
NSUserDefaults.synchronize()
however I keep encountering an error with the
NSUserDefaults.synchronize()
portion.The error states "Missing argument for parameter #1 in call" All the places i've looked seem to use that code with no error. I'm aware that there is going to be/ was recently an update to swift. Did this update cause something to change with the synchronize function, how do I fix this?
You need to call synchronize on standardUserDefaults.
NSUserDefaults.standardUserDefaults().synchronize();
Keep in mind that there is no need to call synchronize.
synchronize is an instance method, so you should call it on an instance, not the class:
NSUserDefaults.standardUserDefaults().synchronize()
However, you shouldn't need to do this.
In the CoreFoundation release notes for OS X 10.8, it was stated:
CFPreferences Synchronization
CFPreferencesSynchronize() (and therefore CFPreferencesAppSynchronize() and -[NSUserDefaults synchronize]) is now automatic in virtually all cases. The only remaining reason to call it is if you need a separate process to be able to synchronously access the values you just set; for example if you set a preference, then post a notification which another process receives and reads the same preference. Most regular applications will never need to do this, and applications that do are encouraged to use an inter-process communication API (for example XPC) to communicate with the other process rather than using the preferences system for IPC.
CFPreferencesSynchronize() is also much faster in 10.8, and will avoid doing any work if there are no outstanding changes to read or write.
And the Foundation release notes for 10.9:
-[NSUserDefaults synchronize] is not generally useful
You should only need to call -synchronize if a separate application will be reading the default that you just set, or if a process that does not use AppKit is terminating. In most applications neither of these should ever occur, and -synchronize should not be called. Note that prior to Mac OS X 10.8.4 there was a bug that caused AppKit to automatically synchronize slightly prematurely during application termination, so preferences set in response to windows closing while the application is terminating might not be saved; this has been fixed.
Does anyone have an iOS job queue similar to Path's Android Priority Job Queue that they don't mind sharing with the community? I am very new to iOS so I am not sure if the platform itself provides such a solution. On android no such thing exists so I had to use the library that Path has generously made available. If iOS itself or Xcode has such a solution/API please point me to it. If not please share yours if you don't mind. Thanks.
Basically I am looking for a job queue that can allow users to send data to server even when there is no network: which means the queue would hold on to the data even if user should turn off the iPhone. And then at some later time, when the system detects network, push the data to the server.
There is a similar question on SO already so I am including it for more detail: How to queue up data for server dispatch on android. The difference is that my question is for iOS and theirs is for android.
Use case
My case is imagining a user is boarding a train in a subway (no network) but decides to send an email. Then close the app, or even turn off the phone. Then an hour later, after user turns phone back on, when network is detected, the app sends the email.
https://github.com/thisandagain/queue is quite promising. It has ability to retry and is persistent.
AFNetworking's request operations and request operation manager could be modified to do this with not too much work.
Needed modifications:
When an AFHTTPRequestOperation fails due to no connectivity, make a copy of the operation and store it (in an NSArray, for example)
Use the built-in reachability manager, and retry the operations in the array when reachability returns
Remove the operations from the array if they're successful
Note that the completion blocks aren't copied when an operation is copied. From the documentation:
-copy and -copyWithZone: return a new operation with the NSURLRequest of the original. So rather than an exact copy of the operation at that particular instant, the copying mechanism returns a completely new instance, which can be useful for retrying operations.
A copy of an operation will not include the outputStream of the original.
Operation copies do not include completionBlock, as it often strongly captures a reference to self, which would otherwise have the unintuitive side-effect of pointing to the original operation when copied.
I don't know of any open source library that has already implemented these modifications, or I'd point you there.
I found very simmilar lib like path's job priority queue
https://github.com/lucas34/SwiftQueue/wiki
Hope this helps someone since this is very old questions but ot might help someone who is still finding like me :)