Where is NSAlert.h in the iOS SDK? - iphone

According to iOS's Using and Creating Error Objects, one can display a error object with the following code.
NSError *theError = nil;
BOOL success = [myDoc writeToURL:[self docURL] ofType:#"html" error:&theError];
if (success == NO) {
// Maybe try to determine cause of error and recover first.
NSAlert *theAlert = [NSAlert alertWithError:theError];
[theAlert runModal]; // Ignore return value.
}
Unfortunately, I am not smart enough to figure out how to include NSAlert.h.
Any help would be appreciated.

That document is referring to the (OS X) AppKit framework. Right after that box, it says:
(UIAlertView, the UIKit class corresponding to NSAlert, has no equivalent method for alertWithError:.)
You can still use UIAlertView, but you'll need to manually populate the title, message, and button strings from the error.

NSAlert isn't availble in UIKit. the example it just an copy past of the OS X doc.
This code in Listing 2-1 uses the
returned NSError to display an error
alert to the user immediately.
(UIAlertView, the UIKit class
corresponding to NSAlert, has no
equivalent method for
alertWithError:.) Error objects in the
Cocoa domain are always localized and
ready to present to users, so they can
often be presented without further
evaluation.

Its in the AppKit framework.
NSAlert
Import that framework to your project in xcode, then use the #include directive at the top of your code
there are also some samples of using NSAlert if you go to that page and look at the "Sample Code". I always do that if I'm unsure of any part of a new framework

Related

Ambiguous reference to member 'close()'

I am trying to create an application that will allow a user to cycle through next/previous text document files in a folder, the way photo-viewing apps will often allow next/previous picture view. It seems to me so far that the most effective way to do this is to replace the document in the currently open window. The edited answer to my previous question on the topic suggests that this is indeed possible. I want to be able to use the document architecture for opening and saving; I don't want to have to generalize the framework, I'm trying to keep it simple. I tried to use the code recommended in the previous question as follows:
let prevDocument = windowController.document
let newDocument = Document(contentsOf: newURL, ofType: myDocumentType) // add do-catch
NSDocumentController.shared.addDocument(newDocument);
newDocument.addWindowController(windowController)
prevDocument.close()
But when I do this, the prevDocument.close() command gives me the odd error "Ambiguous reference to member 'close()'". Another thread tells me that "This kind of error appears when there's more than one variable/method with the same name". OK, but which ones, and how do I fix it? Underneath the "ambiguous reference" error I get two messages: "Found this candidate (Foundation.Stream)" and "Found this candidate (AppKit.NSBezierPath)". A brief look at the docs for Foundation.Stream and NSBezierPath suggests that Foundation.Stream and not NSBezierPath is what I'm trying to work with, but I have no idea how to tell the system that (or why NSBezierPath would be involved in the first place).
The document property of an NSWindowController has type AnyObject?, hence why there's no close method and the compiler struggles to figure out what type of object it could be, such that it could have a close method.
Clicking through to the documentation of the document property in Xcode (ctrl-cmd click) shows a comment that the document property is usually of type NSDocument, which does have a close method. Typecasting is worth a try:
guard let prevDocument = windowController.document as? NSDocument else {
// ...
}
// Rest of your code
Alternatively, if you can guarantee that only one document at a time will be managed by your application:
guard let previousDocument = NSDocumentController.shared.documents.first else {
// ...
return
}
// Rest of your code

IOCreatePlugInInterfaceForService returns mysterious error

I am trying to use some old IOKit functionality in a new Swift 4.0 Mac app (not iOS). I have created a bridging header to use an existing Objective C third party framework, DDHidLib, and I am current working in Xcode 9.
The code that attempts to create a plug in interface for a usb gamepad falls over on IOCreatePlugInInterfaceForService, returning a non-zero error.
The truly bizarre thing is I have an older app created in a previous version of Xcode that uses the same framework and works correctly after opening in the new Xcode 9. This previous project is still Swift using a bridging header for the same Obj-C framework. I have checked the build settings and tried to make everything match, but I get the same result; the old app works but any new apps do not.
Is there a way to either: find out the exact differences in build settings/compilers to see what the elusive difference may be, OR to step into the IOCreatePlugInInterfaceForService IOKit method to see what may be causing the error to be returned in one project but not another?
EDIT: Here is the method that is failing:
- (BOOL) createDeviceInterfaceWithError: (NSError **) error_; {
io_name_t className;
IOCFPlugInInterface ** plugInInterface = NULL;
SInt32 score = 0;
NSError * error = nil;
BOOL result = NO;
mDeviceInterface = NULL;
NSXReturnError(IOObjectGetClass(mHidDevice, className));
if (error)
goto done;
NSXReturnError(IOCreatePlugInInterfaceForService(mHidDevice, kIOHIDDeviceUserClientTypeID,kIOCFPlugInInterfaceID,&plugInInterface,&score));
if (error)
goto done;
//Call a method of the intermediate plug-in to create the device interface
NSXReturnError((*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID) &mDeviceInterface));
if (error)
goto done;
result = YES;
done:
if (plugInInterface != NULL)
{
(*plugInInterface)->Release(plugInInterface);
}
if (error_)
*error_ = error;
return result;
}
In the old version that works, IOCreatePlugInInterfaceForService always returns a value of 0. In all the versions that don't work, the return value appears to always be -536870210. The mHidDevice in this function is the io_object_t handle for the device.
EDIT2: Here is the IORegistryExplorer page for the device
Finally managed to resolve this after weeks of head scratching. The new Xcode 9 uses app sandboxing to basically prevent access to USB, bluetooth, camera and microphone etc. by default in a new app. Once I switched this off it reverted to it's expected behaviour.
Glad it was such a simple answer in the end but disappointed Xcode does not provide more descriptive error messages or responses to let a user know they are essentially preventing themselves from accessing the parts of the system they need.
Looks like kIOReturnNoResources is returned if the loop at the end of IOCreatePlugInInterfaceForService completes with haveOne == false for whatever reason. Perhaps Start() is returning false because another process or driver already has exclusive access? I'd check what clients the device has in IORegistryExplorer.
This error also happens when an application is trying to access the camera or bluetooth on MacOS 10.14 and higher. Permission shall be granted either explicitly by user (pop-up window), or through the Security & Privacy. The application should check for permission as shown here.

Unit test in IOS

I have a UIbutton in my app. When I click the button, it removes the last object in a NSMutableArray. For this, I want to write unit tests.Please any one give me your suggestion.
I use this code for knowing when a click on the UIButton was performed:
[viewControllerObject.backButton1 sendActionsForControlEvents:UIControlEventTouchUpInside];
Thanks,
Ricky.
At a "unit" level there are two things you're testing:
does tapping the button send the action method?
does the action method remove the last object from an array?
Ignore the first one, that's Apple's problem (or charitably it's an integration test). The second is straightforward if you think about the Assemble, Act, Assert process:
Assemble: build your view controller and its content array.
Act: call the action method.
Assert: check that the last object was removed.
-(void)testRemovalOfLastObjectOnButtonAction
{
//... build and populate the view controller
id lastObject = [array lastObject];
[viewController buttonTapped: sender];
STAssertFalse([array containsObject: lastObject], #"Object %# should be removed", lastObject);
}
Note I test explicitly whether the last object was removed, not whether the count was decremented: that could happen if any object were removed.
You can do this in several different ways. A suggestion would be to watch this great tutorial
The video explains how to unit test in UIKit.
XCode has native support for Unit Tests. If you start a new project, look for the check mark that says 'Include Unit Test'. If you use that, you will have a folder called <project_name>Tests. Open the .m file in there, and you'll see a - (void)testExample method where you can put your tests.
You can use a number of functions to test, like STAssertTrue and STAssertNotNil. Check out the Apple docs here: https://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/UnitTesting/03-Writing_Test_Case_Methods/writing_tests.html#//apple_ref/doc/uid/TP40002143-CH4-SW1
In your case, you could probably do something like this:
NSInteger arrayCount = mArray.count;
[yourInstance performButtonAction];
STAssertEquals(arrayCount -1, mArray.count);

Core data edit function

I already have a tableView with data in it. IF you tap a cell/row it pushes to an edit type of view. Is there anyway to edit core data's data other than: By edit, i mean i already have data inserted into my context. I have loaded my data into my view, the user can change the existing data, and re save it.
.h
//Below is the entity/entity's class name 'Amm'
Amm *amm;
.m
-(IBAction)save
{
[self.amm setValue:self.nameField.text forKey:#"name"];
[self.amm setValue:self.nicknameField.text forKey:#"nickname"];
[self.navigationController popViewControllerAnimated:YES];
NSError *error;
if (![self.managedObjectContext save:&error]) {
//Handle Error
}
}
I want this code to work, however the design pattern of my app isnt allowing this code to work for me as it does in other parts of my app. Thank you very much for any and all help!
I assume from what you've said you have:
A table view listing your managed objects
A view where you can edit the values of a managed object
A save button bound to the save method
What's the actual issue? I'm assuming when you tap save that:
The values in self.nameField.text isn't setting self.amm.name
The values in self.nicknameField.text isn't setting self.amm.nickname
Is that right? If so perhaps try the following code to set the managed object values:
self.amm.name = self.nameField.text
self.amm.nickname = self.nicknameField.text
If that's not the issue and you are actually setting the managed object values properly, is it that you just need to refresh the table-view? Perhaps use some NSLog commands to log every step of the applications progress.

iPhone: Reading Text From File and UISegmentedControl

First off, I'm a complete beginner.
That said, I thought an ambitious longer-term project/learning experience would be to create an app that displayed daily quotes, like those cheesy day-by-day calendars our grandmothers have in their bathrooms. I want it to have two per day, each one represented by a tab in a UISegmentedControl. That's the long term. Right now I'd be happy with getting a single day's worth of quotes functioning.
Onto the questions:
How can I get text saved in a .txt or .rtf file to be displayed in a UITextView? Preferably without using 'stringWithContentsOfFile,' since Xcode is telling me that's deprecated.
How can I get content from a different file (or maybe a different portion of the same file...?) to be displayed when the user taps the second segment?
If I can get it running so that those two conditions are met and I understand what's going on, I'll consider the day a success. Thanks!
1.
NSError *error = nil;
NSStringEncoding stringEncoding;
NSString *fileText = [NSString stringWithContentsOfFile:#"/path" usedEncoding:&stringEncoding error:&error];
myTextView.text = fileText;
The error and encoding are optional, and you can pass in nil for both. But if you care about the error, or what encoding the file was in they will have useful info in them after the string is created.
2.
Set the valueChanged outlet in Interface Builder to an IBAction on your controller, such as setSegmentValue:. Then, assuming you have an array of quote strings:
- (IBAction)setSegmentValue:(id)sender {
UISegmentedControl *control = (UISegmentedControl*)sender;
NSString *quote = [quotes objectAtIndex:control.selectedSegmentIndex];
myTextView.text = quote;
}
Even though stringWithContentsOfFile: is deprecated, stringWithContentsOfFile:usedEncoding:error: is not. That is the standard method to use for reading from files.
As for the second question, you simply test the state of the segmented control and perform as action based on it. Admittedly this is a high level answer but should get you going.