NSTask / Process deprecated methods and properties - objective-c

In the most recent Apple documentation both NSTask and Process have several deprecated methods and properties, although there's nothing marked with an API Availability Macro.
Instance Properties
#property(copy) NSString *launchPath;
#property(copy) NSString *currentDirectoryPath;
var launchPath: String? { get set }
var currentDirectoryPath: String { get set }
Instance Methods
- (void)launch;
func launch()
Type Methods
+ (NSTask *)launchedTaskWithLaunchPath:(NSString *)path
arguments:(NSArray<NSString *> *)arguments;
class func launchedProcess(launchPath path: String,
arguments: [String]) -> Process
There seemingly are no replacements available, so what gives?

There seemingly are no replacements available
There are, the API is now URL related
Instance Properties
#property(copy) NSURL *executableURL;
#property(copy) NSURL *currentDirectoryURL;
var executableURL: URL? { get set }
var currentDirectoryURL: URL? { get set }
Instance Methods
- (BOOL)launchAndReturnError:(out NSError * _Nullable *)error;
func run() throws
Type Methods
+ (NSTask *)launchedTaskWithExecutableURL:(NSURL *)url
arguments:(NSArray<NSString *> *)arguments
error:(out NSError * _Nullable *)error
terminationHandler:(void (^)(NSTask *))terminationHandler;
class func run(_ url: URL,
arguments: [String],
terminationHandler: ((Process) -> Void)? = nil) throws -> Process

Related

Convert Objective-C to Swift to Mock S3

I want to mock S3, but I seem unable to come up with the Swift equivalent of the following:
- (void)listObjects:(AWSS3ListObjectsRequest *)request completionHandler:(void (^ _Nullable)(AWSS3ListObjectsOutput * _Nullable response, NSError * _Nullable error))completionHandler;
I've tried quite a few alternatives:
// func listObjects(request: AWSS3ListObjectsRequest) -> AWSTask<AWSS3ListObjectsOutput>
// func listObjects(request: AWSS3ListObjectsRequest, completionHandler: (AWSTask<AWSS3ListObjectsOutput>) -> AnyObject?)
func listObjects(request: AWSS3ListObjectsRequest, completionHandler: () -> AWSTask<AWSS3ListObjectsOutput>)
// - (void)listObjects:(AWSS3ListObjectsRequest *)request completionHandler:(void (^ _Nullable)(AWSS3ListObjectsOutput * _Nullable response, NSError * _Nullable error))completionHandler;
ButI can't seem to get one that AWSS3 conforms to. I need to do this to mock the function in Swift.
func listObjects(request: AWSS3ListObjectsRequest, completionHandler: ((AWSS3ListObjectsOutput?, Error?) -> Void)?) {
}

app broke after Xcode update

I have a Swift app, with some Objective-C code mixed in. It was working yesterday, but this morning I updated XCode and now everything had gone to hell!
Firstly, after updating, I clicked the XCode popup box to allow it to upgrade my app to Swift4. This is where the problems started.
I have a Swift class called RestClient with the following 4 functions (among others):
class func getInstance() -> RestClient {
if (gRestClient == nil) {
let prefs:UserDefaults = UserDefaults.standard
return RestClient(username: prefs.string(forKey: "username")!, password: prefs.string(forKey: "password")!)
}
return gRestClient!
}
class func getUsername() -> String {
if (gUsername == nil) {
let prefs:UserDefaults = UserDefaults.standard
gUsername = prefs.string(forKey: "username")!
}
return gUsername!
}
class func getPassword() -> String {
if (gPassword == nil) {
let prefs:UserDefaults = UserDefaults.standard
gPassword = prefs.string(forKey: "password")!
}
return gPassword!
}
public func getServer() -> String {
return MAIN_SERVER;
}
Then in my /Objective-C/ folder, I have some more files, once of which is called RestClientObj.m. In here, I have this lines of code:
NSString* url = [NSString stringWithFormat:#"%#/receipt/email/%#/%#/", [[RestClient getInstance] getServer], rrn, emailAddress];
NSString *authStr = [NSString stringWithFormat:#"%#:%#", [RestClient getUsername], [RestClient getPassword]];
So as you can see, I'm calling the RestClient.swift from here. The RestClientObj.h is as follows:
#ifndef RestClientObj_h
#define RestClientObj_h
#endif /* ResClientObj_h */
#interface RestClientObj : NSObject {
}
+(BOOL) sendSMS:(NSString *)rrn mn:(NSString *)mobileNumber;
+(BOOL) sendEmail:(NSString *)rrn mn:(NSString *)emailAddress;
#end
This whole upgrade is causing other problems too. I have another class with the following error:
No visible #interface for 'AppDelegate' declares the selector 'managedObjectContext'
on the line:
appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *context = [appDelegate managedObjectContext]; <-ERROR
Can anyone shed any light on this?
EDIT: Here's some code from the AppDelegate class:
lazy var managedObjectContext: NSManagedObjectContext? = {
// Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
let coordinator = self.persistentStoreCoordinator
if coordinator == nil {
return nil
}
var managedObjectContext = NSManagedObjectContext()
managedObjectContext.persistentStoreCoordinator = coordinator
return managedObjectContext
}()
Just to close this off.
The issue was missing the #obj identifier before the variable declaration to make it visible to my objective-c code, in combination with the XCode Swift Upgrade wizard renaming some functions.

OSX: Quit app correctly upon logout

Every time I am trying to log out the current user (not Fast User Switchting!) I get a message from macOS (excuse me if its not exactly the message, I am getting it in german): "Unable to logout, because application "com.my.app" does not quit".
What do I need in order to avoid this? I currently have this in my AppDelegate:
- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
{
return NSTerminateNow;
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return true;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
selector: #selector(receiveLogOffOrShutdown:)
name: NSWorkspaceWillPowerOffNotification object: NULL];
}
-(void) receiveLogOffOrShutdown: (NSNotification*) note
{
[application stop:nil];
}
What I have observed for example is that receiveLogOffOrShutdown is never triggered. As well as applicationShouldTerminate never triggers a breakpoint.
Am I missing something here?
Use NSApp.terminate method
Objective C
-(void)relaunch {
int processIdentifier = NSProcessInfo.processInfo.processIdentifier;
NSString *path = [NSBundle mainBundle].executablePath;
NSArray *arg = [NSArray arrayWithObjects:[NSString stringWithFormat:#"%d",processIdentifier], nil];
[NSTask launchedTaskWithLaunchPath:path arguments:arg];
[NSApp terminate:self];
}
Swift
func relaunch() {
let processIdentifier: Int32 = NSProcessInfo.processInfo().processIdentifier
let path = NSBundle.mainBundle().executablePath! as NSString
// let myPath: String = "\(path.fileSystemRepresentation)"
NSTask.launchedTaskWithLaunchPath(path as String, arguments: ["\(processIdentifier)"])
NSApp.terminate(self)
}
func terminate(sender: AnyObject?)
When invoked, this method performs several steps to process the termination request
Hope this help you.

Call Swift function with completion handler in objective c

I am trying to call a Swift function that contains a completion handler in an objective C class, but I am not sure how to implement it.
This is my Swift Code
#objc class textToSpeech:NSObject{
func toSpeech(word: NSString, sucess:()->Void) -> NSURL {
let tempDirectory = NSURL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let tempFile = tempDirectory.URLByAppendingPathComponent((word as String) + ".wav")
let tts = TextToSpeech(username: "xxxxxx", password: "xxxxxx")
tts.synthesize(word as String,
voice: SynthesisVoice.GB_Kate,
audioFormat: AudioFormat.WAV,
failure: { error in
print("error was generated \(error)")
}) { data in
data.writeToURL(tempFile, atomically: true)
print("createdURL")
print(tempFile)
sucess();
}
return tempFile
}
How would I write the function call in objective c. I have already completed setting up the project so that I can call swift functions from objective c.
For example you have this code:
#objc class PDTextToSpeech: NSObject{
func toSpeech(word: NSString, success: () -> Void) -> NSURL {
// ...
return NSURL()
}
}
So you could easily bridge you Swift code in obj-c with #import "<ModuleName>-Swift.h"
where you project name.
Then you can call:
[[PDTextToSpeech new] toSpeech:#"String" success:^{
NSLog(#"Success");
}];
I was using PDTextToSpeech as class name, because it's preferable to call classes in obj-c with uniq prefix. If you project called TestProject - you can use TP prefix.
I guess it should look like this:
textToSpeech* text = [[textToSpeech alloc] init];
[text word:#"some text" sucess:^{
NSLog(#"success");
}];

Xcode updating label text from function

I'm having trouble with some objective-c in Xcode. I'm trying to adapt an example from the DiskArbitration framework, and I'm getting stuck. This example sets a callback whenever the framework sees a disk. From the callback, I want to update a label.
#interface AVRecorderDocument ()
#property (assign) IBOutlet NSTextField *labelSpaceLeft;
#end
#implementation AVRecorderDocument
....
-id(init){
...
DASessionRef sessionDA = DASessionCreate(kCFAllocatorDefault);
DARegisterDiskAppearedCallback(sessionDA, kDADiskDescriptionMatchVolumeMountable, diskAppearedCallback, 0);
DASessionScheduleWithRunLoop(sessionDA, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
...
}
static void diskAppearedCallback(DADiskRef disk, void* context)
{
CFDictionaryRef description = DADiskCopyDescription(disk);
NSLog(#"Disk appeared: %#", description);
NSLog(#"Disk Name: %#", CFDictionaryGetValue(description, CFSTR("DADeviceModel")));
// [_labelSpaceLeft setStringValue:[NSString CFDictionaryGetValue(description, CFSTR("DADeviceModel"))]];
CFRelease(description);
}
...
#end
The commented line inside the static function is what i've tried, but I get a "Use of undeclared identifier" error.
I've also tried converting the function to a method, which the compiler is ok with, but then I don't know how to properly call this from the DARegisterDiskAppearedCallback line at the top.
-(void)diskAppearedCallback:(DADiskRef *)disk context:(void *)context{
CFDictionaryRef description = DADiskCopyDescription(*disk);
NSLog(#"Disk appeared: %#", description);
NSString *spaceLeft = CFDictionaryGetValue(description, CFSTR("DADeviceModel"));
NSLog(#"Disk Name: %#", CFDictionaryGetValue(description, CFSTR("DADeviceModel")));
[labelSpaceLeft setStringValue:[NSString stringWithFormat: #"%#", spaceLeft]];
CFRelease(description);
}
**UPDATE: Here is a gist of the project: https://gist.github.com/anonymous/cb1c5795536ca15ef4e3
OK so the issue is that you are basically mixing C and Objective-C. The callback function diskAppearedCallback is a C function and is not part of that class, even though it is defined between #implementation and #end. It therefore doesn't have access to _labelSpaceLeft.
To fix the issue you need to get the callback function to call a method on that class instance, so when registering the callback, pass the instance in the last parameter. This is precisely what context pointers are for in callback functions.
DARegisterDiskAppearedCallback(sessionDA,
kDADiskDescriptionMatchVolumeMountable,
diskAppearedCallback,
self); // HERE
and then context in the callback function will be a pointer to the class instance:
static void diskAppearedCallback(DADiskRef disk, void* context) {
CFDictionaryRef description = DADiskCopyDescription(*disk);
NSLog(#"Disk appeared: %#", description);
NSString *spaceLeft = CFDictionaryGetValue(description, CFSTR("DADeviceModel"));
NSLog(#"Disk Name: %#", CFDictionaryGetValue(description, CFSTR("DADeviceModel")));
// HERE
AVRecorderDocument *instance = (AVRecorderDocument *)context;
[instance.labelSpaceLeft setStringValue:spaceLeft];
CFRelease(description);
}