I have been working with xcode 4 for a few months now with no problem, well with some problems but that is another story, and now have a weird problem. I can not add any new methods... What I mean to say is when I add a new method xcode doesn't recognize it. The tag follow doesn't see it and the debugger errors saying there is no method by that name. However, the method just above it with the exact same signature minus the name works famously.
Has anyone ever seen this before? If so could you please send me in the right direction. Any help and I would be eternally grateful.
- (void)showMyCalendar:(TKCalendarMonthView*) calendar1
{
if (calendar1.frame.origin.y == -calendar1.frame.size.height+calendarShadowOffset)
{
[self displayCalendar:calendar1];
}
else
{
[self hideCalendar:calendar1];
}
[self showMyCalendar:calendar1]; // If I put a call here xcode sees it.
}
- (void)anotherMethod:(TKCalendarMonthView*) calendar1
{
if (calendar1.frame.origin.y == -calendar1.frame.size.height+calendarShadowOffset)
{
[self displayCalendar:calendar1];
}
else
{
[self hideCalendar:calendar1];
}
[self showMyCalendar:calendar1]; // If I put a call here xcode DOES NOT see it.
}
Thanks,
Ed
Did you include a method definition in your .h file for the .m file that this method is contained in?
- (void)anotherMethod:(TKCalendarMonthView*) calendar1;
Related
I have an NSOpenPanel with an accessoryView; in this view the user chooses a couple of radio button to change the allowed types. When the panel opens, the right files are enabled, the other disabled. Ok, good.
Now the user changes the radio buttons, the viewController of the accessoryView observe the changes in the radio button matrix and changes consequently the allowedTypes of the NSOpenPanel.
After that, following Apple documentation, it calls -validateVisibleColumns, but nothing visible changes in the panel. That is: the right files seems disabled: I can choose them but they are in grey!
Another wrong effect: I select a file (enabled), change the file type, the (now wrong) file remains selected, with the OK button enabled: but this is the wrong file type! It seems that the change happens but the interface doesn't know!
My code is (selected is bound to the matrix of radio button):
- (void)observeValueForKeyPath.....
{
NSString *extension = (self.selected==0) ? #"txt" : #"xml";
[thePanel setAllowedFileTypes:#[extension, [extension uppercaseString]]];
[thePanel validateVisibleColumns];
}
I first tried to insert a call
[thePanel displayIfNeeded]
then I tried with
[thePanel contentView] setNeedsDisplay]
with no results. I also tried to implement the panel delegate method panel:shouldEnableURL:, that should be called by validateVisibleColumns: I just found that it was called just once, at the opening of NSOpenPanel.
Can someone have an idea why this happens? I tried all this with sandboxed and not-sandboxed applications, no difference. I'm developing on ML with 10.8 sdk.
Edit
By now the only way to avoid the problem is to implement panel:validateURL:error, but this is called after the user clicked 'open' and it's very bad.
I have the exact same problem, under 10.9, non-sandboxed, and have spent the better part of this DAY trying to find a solution!
After A LOT of tinkering and drilling down through the various classes that make up the NSOpenPanel (well NSSavePanel really) I did find a way to force the underlying table to refresh itself:
id table = [[[[[[[[[[[[_openPanel contentView] subviews][4] subviews][0] subviews][0] subviews][0] subviews][7] subviews][0] subviews][1] subviews][0] subviews][0] subviews][0] subviews][2];
[table reloadData];
Of course, the best way to code this hack would be to walk down the subview list ensuring the right classes are found and eventually caching the end table view for the subsequent reloadData calls.
I know, I know, this is a very ugly kludge, however, I can not seem to find any other answer to fix the issue, other than "file a bug report". Which, from what I can see online people have been doing since 1.8! :(
EDIT:
Here is the code I am now using to make my NSOpenPanel behave correctly under 10.9:
- (id) openPanelFindTable: (NSArray*)subviews;
{
id table = nil;
for (id view in subviews) {
if ([[view className] isEqualToString: #"FI_TListView"]) {
table = view;
break;
} else {
table = [self openPanelFindTable: [view subviews]];
if (table != nil) break;
}
}
return table;
}
- (void) refreshOpenPanel
{
if (_openPanelTableHack == nil)
_openPanelTableHack = [self openPanelFindTable: [[_openPanel contentView] subviews]];
[_openPanelTableHack reloadData];
[_openPanel validateVisibleColumns];
}
This code requires two instance variables _openPanel and _openPanelTableHack to be declared in order to work. I declared _openPanel as NSOpenPanel* and _openPanelTableHack is declared as id.
Now, instead of calling [_openPanel validateVisibleColumns] I call [self refreshOpenPanel] to force the panel to update the filenames as expected. I tried caching the table view when the NSOpenPanel was created, however, it seems that once you "run" the panel the table view changes, so I have to cache it on the first update instead.
Again, this is a GIANT hack, however, I do not know how long it will take Apple to fix the issue with accessory views and the file panels, so for now, this works.
If anyone has any other solutions that are not huge kludges please share! ;)
An implementation in swift of Eidola solution.
Biggest difference is that I search for a NSBrowser (sub)class rather than a specific class name. Tested on 10.10 (not sandboxed).
private weak var panelBrowser : NSBrowser? //avoid strong reference cycle
func reloadBrowser()
{
if let assumedBrowser = panelBrowser
{
assumedBrowser.reloadColumn(assumedBrowser.lastColumn)
}
else if let searchResult = self.locateBrowser(self.panel?.contentView as! NSView)
{
searchResult.reloadColumn(searchResult.lastColumn)
self.panelBrowser = searchResult //hang on to result
}
else
{
assertionFailure("browser not found")
}
}
//recursive search function
private func locateBrowser(view: NSView) -> NSBrowser?
{
for subview in view.subviews as! [NSView]
{
if subview is NSBrowser
{
return subview as? NSBrowser
}
else if let result = locateBrowser(subview)
{
return result
}
}
return nil
}
Edit:
Ok, so the code above will not work all the time. If it's not working and a file is selected (you can see the details/preview), then you have to reload the last to one column instead of the last column. Either reload the last two columns (make sure there are at least 2 columns) or reload all columns.
Second problem: if you reload the column, then you lose the selection. Yes, the selected files/directory will still be highlighted, but the panel will not return the correct URL's.
Now I am using this function:
func reloadBrowser()
{
//obtain browser
if self.panelBrowser == nil
{
self.panelBrowser = self.locateBrowser(self.panel?.contentView as! NSView)
}
assert(panelBrowser != nil, "browser not found")
//reload browser
let panelSelectionPatch = panelBrowser.selectionIndexPaths //otherwise the panel return the wrong urls
if panelBrowser.lastColumn > 0
{
panelBrowser.reloadColumn(panelBrowser.lastColumn-1)
}
panelBrowser.reloadColumn(panelBrowser.lastColumn)
panelBrowser.selectionIndexPaths = panelSelectionPatch
}
Just upgrade to xcode 6.3 (on Yosemite 10.10.3) and its ok. Apple fixed the bug (no more need Eidola Hack).
I'm trying to figure out how to limit my NSDocument based application to one open document at a time. It is quickly becoming a mess.
Has anyone been able to do this in a straightforward & reliable way?
////EDIT////
I would like to be able to prompt the user to save an existing open document and close it before creating/opening a new document.
////EDIT 2
I'm now trying to just return an error with an appropriate message if any documents are opening -- however, the error message is not displaying my NSLocalizedKeyDescription. This is in my NSDocumentController subclass.
-(id)openUntitledDocumentAndDisplay:(BOOL)displayDocument error:(NSError **)outError{
if([self.documents count]){
NSMutableDictionary* dict = [NSMutableDictionary dictionaryWithObject:#"Only one document can be open at a time. Please close your document." forKey:NSLocalizedDescriptionKey];
*outError = [NSError errorWithDomain:#"Error" code:192 userInfo:dict];
return nil;
}
return [super openUntitledDocumentAndDisplay:displayDocument error:outError];
}
It won't be an easy solution, since it's a pretty complex class, but I would suggest that you subclass NSDocumentController and register your own which disables opening beyond a certain number of documents. This will allow you to prevent things like opening files by dropping them on the application's icon in the dock or opening in the finder, both of which bypass the Open menu item.
You will still need to override the GUI/menu activation code to prevent Open... from being available when you have a document open already, but that's just to make sure you don't confuse the user.
Your document controller needs to be created before any other document controllers, but that's easy to do by placing a DocumentController instance in your MainMenu.xib and making sure the class is set to your subclass. (This will cause it to call -sharedDocumentController, which will create an instance of yours.)
In your document controller, then, you will need to override:
- makeDocumentForURL:withContentsOfURL:ofType:error:
- makeUntitledDocumentOfType:error:
- makeDocumentWithContentsOfURL:ofType:error:
to check and see if a document is already open and return nil, setting the error pointer to a newly created error that shows an appropriate message (NSLocalizedDescriptionKey).
That should take care of cases of drag-and-drop, applescript,etc.
EDIT
As for your additional request of the close/save prompt on an opening event, that's a nastier problem. You could:
Save off the information (basically the arguments for the make requests)
Send the -closeAllDocumentsWithDelegate:didCloseAllSelector:contextInfo: with self as a delegate and a newly-created routine as the selector
When you receive the selector, then either clear out the saved arguments, or re-execute the commands with the arguments you saved.
Note that step 2 and 3 might need to be done on delay with performSelector
I haven't tried this myself (the rest I've done before), but it seems like it should work.
Here's the solution I ended up with. All of this is in a NSDocumentController subclass.
- (NSInteger)runModalOpenPanel:(NSOpenPanel *)openPanel forTypes:(NSArray *)extensions{
[openPanel setAllowsMultipleSelection:NO];
return [super runModalOpenPanel:openPanel forTypes:extensions];
}
-(NSUInteger)maximumRecentDocumentCount{
return 0;
}
-(void)newDocument:(id)sender{
if ([self.documents count]) {
[super closeAllDocumentsWithDelegate:self
didCloseAllSelector:#selector(newDocument:didCloseAll:contextInfo:) contextInfo:(void*)sender];
}
else{
[super newDocument:sender];
}
}
- (void)newDocument:(NSDocumentController *)docController didCloseAll: (BOOL)didCloseAll contextInfo:(void *)contextInfo{
if([self.documents count])return;
else [super newDocument:(__bridge id)contextInfo];
}
-(void)openDocument:(id)sender{
if ([self.documents count]) {
[super closeAllDocumentsWithDelegate:self
didCloseAllSelector:#selector(openDocument:didCloseAll:contextInfo:) contextInfo:(void*)sender];
}
else{
[super openDocument:sender];
}
}
- (void)openDocument:(NSDocumentController *)docController didCloseAll: (BOOL)didCloseAll contextInfo:(void *)contextInfo{
if([self.documents count])return;
else [super openDocument:(__bridge id)contextInfo];
}
Also, I unfortunately needed to remove the "Open Recent" option from the Main Menu. I haven't figured out how to get around that situation.
For what ever reason my xcode has decided it doesn't like me... I'm getting the error stated in the title on this line
- (void)tableViewSelectionDidChange:(NSNotification *)notification
{
NSInteger row = [_tableView selectedRow];
if (row == –1) //<---- this line
{
return;
}
NSString *selectedVoice = [_voices objectAtIndex:row];
[_speechSynth setVoice:selectedVoice];
NSLog(#"new voice = %#", selectedVoice);
}
I do believe that it has something to do with _tableView being befuddled because when I attempted to get the IDE to help me to type (you know when it guesses what you might what to finish your word with by doing an API lookup of available functions) it doesn't show selectedRow as a possibility :(
incase it's needed i've put the .m and .h in a pastebin to save some space on your screens... FYI I'm following the Coca Programming for Mac OSX fourth Edition chapter 6.10
In your line
if (row == –1)
the minus-sign is not the real minus-sign, but an "EN DASH" (Unicode U+2013). Perhaps you accidentally pressed the option-key together with the minus-key when typing that code.
Replacing that character with a minus-sign fixes the problem.
UITableView doesn't have a method called selectedRow.
Perhaps you should be using:
- (NSIndexPath *)indexPathForSelectedRow
On OSX, I am using XCode to make a desktop app with a webview in it. The webview loads ok, and I can dynamically load content into it - but when I click on links inside the webview, they are not followed. They change color, but no new page is loaded. If I code my links with javascript like this - then they work.
link there
Is there an Objective-C one liner that allows links to be followed inside web-views?
Is there another issue I am not aware of here?
The links at the top of Gmail open in a new window. To make them work you have to implement at least the WebUIDelegate methods webView:createWebViewWithRequest: and webViewShow:. If you simply want to open all links in the same web view, you could return it from webView:createWebViewWithRequest: instead of creating a new one.
Turns out it was because I had code I copied form the web with some custom function to ignore WebPolicyDecisionListener...
Sorry for asking question without giving all the details - all this objective-c is new to me, I don't know which bits do what yet. I do some pointing and clicking, and then some coding - I don't know exactly how that all links up. With other languages, you have the whole program in one place - it takes a bit of a learning curve to get used to... but I digress.
I fixed by adding some comments - see code below...
- (void)webView:(WebView *)aWebView
decidePolicyForNavigationAction:(NSDictionary *)actionInformation
request:(NSURLRequest *)request
frame:(WebFrame *)frame
decisionListener:(id < WebPolicyDecisionListener >)listener
{
if ([self requestIsLinkClick:actionInformation]) {
if ([#"method" isEqual:[[request URL] scheme]]) {
SEL selector = NSSelectorFromString([[request URL] resourceSpecifier]);
if ([prototypeDelegate respondsToSelector:selector]) {
[prototypeDelegate performSelector:selector];
}
}
// [listener ignore];
} // else {
[listener use];
//}
}
m new to objective-c, i have made a application of login page in which i have used UISwitch to remember d login details if switch is in on mode. i have done with to remember the login details but problem is that how to use the switch on/off condition. Thanx in advance
The easiest solution of all :)
if (switchValue.on){
//Remember Login Details
}
else{
//Code something else
}
You would add a conditional statement somewhere in your code depending on the switch's on property. Let's say, for example, that you remember login details in a method called rememberLoginDetails. What you would do is, when some action is triggered (the user leaves the login page, for example):
if([yourSwitch isOn]) {
[self rememberLoginDetails];
} else {
// Do nothing - switch is not on.
}
The important method here is the isOn method for the UISwitch yourSwitch. isOn is the getter for the switch's on property, which is a BOOL property containing YES if the switch is on, and NO if it is not.
For more information, you can see the UISwitch class reference, specifically the part about isOn.
if you want to remember the login details just the moment where the user TURN ON the switch, you can done it by create an Action.
- (IBAction)yourSwitch:(id)sender {
if([sender isOn]){
//do your stuff here
}else{
}
}
I believe the code needs to be this:
if([yourSwitch isOn] == YES) {
[self rememberLoginDetails];
} else {
// Do nothing - switch is not on.
}
This is another solution, if your UISwitch is in a tableView
1 add this code in "tableView:cellForRowAtIndexPath:" method
[switchControl addTarget:self action:#selector(switchChanged:) forControlEvents:UIControlEventValueChanged];
2 add this method
- (void) switchChanged:(id)sender {
UISwitch *switchControl = sender;
NSLog( #"The switch is %#", switchControl.on ? #"ON" : #"OFF" );
}
if(switchValue.isOn){
[switchValue setOn:NO];
} else {
[switchValue setOn:YES];
}
i had the same problem, i had the name of the UISwitch = Selected
i changed it to another name and it worked.
This is another solution for that question.
if (switchValue.on == YES)
{
// Code...
}
else
{
// Other code...
}