Objective C: Code Understanding - objective-c

I have the following code:
- (IBAction)buttonSectionPressed:(id)sender {
if ([self.switchReloadOnlyDontToggleVissibility isOn]) {
[self updateCells:self.section2Cells];
} else {
BOOL hide = ([sender tag] == 0);
[self cells:self.section2Cells setHidden:hide];
}
[self reloadDataAnimated:([self.switchAnimated isOn])];
}
I have a question with
BOOL hide = ([sender tag] == 0);
Is it checking to see if (sender.tag == 0) then assign it to hide? So, (if sender.tag != 0), hide does not exist?

This expression works as follows:
Evaluates [sender tag]
Compares the result to zero
If the result is zero, hide is set to YES; otherwise, it is set to NO.
This could also be done with the equivalent expression that uses property syntax:
BOOL hide = (sender.tag == 0);
Finally, you can drop the hide variable altogether:
[self cells:self.section2Cells setHidden:(sender.tag == 0)];

Related

Webpages loaded in WKWebView does not respond to keypress events

I want to enable keyboard shortcuts like Cmd+c , Cmd+v to work on webpages loaded inside WKWebView, but cannot find a solution.
Webview on the other hand has methods like Copy/Paste/Cut which could be leveraged by overriding (void)keyDown:(NSEvent *)event method. But WKWebView does not seem to have any similar funtion.
In WebView i could do something like
- (void)keyDown:(NSEvent *)event {
NSString *s = [event charactersIgnoringModifiers];
if (s == nil)
return;
if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask)
{
if ([s caseInsensitiveCompare:#"a"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(selectAll:)])
[self.contentView selectAll:self];
}
else if ([s caseInsensitiveCompare:#"c"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(copy:)])
[self.contentView copy:self];
}
else if ([s caseInsensitiveCompare:#"v"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(paste:)])
[self.contentView paste:self];
}
else if ([s caseInsensitiveCompare:#"x"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(cut:)])
[self.contentView cut:self];
}
else if ([s caseInsensitiveCompare:#"z"] == NSOrderedSame)
{
[self.contentView undo];
}
}
else
{
[super keyDown:event];
} }
In the above code self.contentView points to a WebView object

Dictionary getting allocated every time

I have two views. In class one I have table with custom cell, where am re-using the cell for three times. I wanted to update table cell text of each row with selected text from another class. I have implemented protocol to take the text value from another class and updating. For storing each row value am using NSDictionary. So that I can take the dictionary value and update in my cellforrowatindexpath to update cell text value. My code,
Class A - Objective C :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"challengeTableCell";
cell = (EnrollmentChallengeTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[EnrollmentChallengeTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
cell.answerTextfield.delegate = self;
if (indexPath.row == 0) {
cell.questionTitleLabel.text = #"Challenge Question 1";
cell.questionLabel.tag = 100;
cell.questionLabel.textColor = [UIColor blackColor];
NSString *user1 = [myDict objectForKey:#"firstQuestion"];
NSLog(#"firstquestion: %#",user1);
}
else if (indexPath.row == 1) {
cell.questionTitleLabel.text = #"Challenge Question 2";
cell.questionLabel.tag = 101;
NSString *user2 = [myDict objectForKey:#"secondQuestion"];
NSLog(#"secondQuestion: %#",user2);
}
else {
cell.questionTitleLabel.text = #"Challenge Question 3";
cell.questionLabel.tag = 102;
NSString *user3 = [myDict objectForKey:#"thirdQuestion"];
NSLog(#"thirdQuestion: %#",user3);
}
if (cell.questionLabel.tag == 100 || cell.questionLabel.tag == 101 || cell.questionLabel.tag == 102) {
UITapGestureRecognizer* gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(selectQuestion:)];
[cell.questionLabel setUserInteractionEnabled:YES];
[cell.questionLabel addGestureRecognizer:gesture];
}
return cell;
}
-(void)selectQuestion:(UITapGestureRecognizer *) sender
{
CGPoint touchLocation = [sender locationOfTouch:0 inView:challengeQuestionsTable];
newIndexPath = [challengeQuestionsTable indexPathForRowAtPoint:touchLocation];
selectQuestionVC = [EnrollmentSelectQuestionViewController instantiate];
selectQuestionVC.questionDelegate = self;
[self presentViewController:selectQuestionVC animated:YES completion:nil];
}
#pragma mark - Table Selection Delegate
-(void)valueChanged:(NSString *)questionString {
//[challengeQuestionsTable reloadRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationNone];
passedValue = questionString;
NSLog(#"questionvalue: %#",passedValue);
NSLog(#"mydict: %lu",(unsigned long)[myDict count]);
cell = [challengeQuestionsTable cellForRowAtIndexPath:newIndexPath];
NSLog(#"you have selected index: %ld", (long)newIndexPath.row);
[[NSUserDefaults standardUserDefaults] setInteger:newIndexPath.row forKey:#"SelectedIndex"];
[[NSUserDefaults standardUserDefaults] synchronize];
// NSInteger numberOfRows = [challengeQuestionsTable numberOfRowsInSection:[indexPath section]];
NSLog(#"indexpath row: %ld",newIndexPath.row);
if (newIndexPath.row == 0) {
[myDict setValue:passedValue forKey:#"firstQuestion"];
} else if (newIndexPath.row == 1) {
[myDict setValue:passedValue forKey:#"secondQuestion"];
} else {
[myDict setValue:passedValue forKey:#"thirdQuestion"];
}
NSLog(#"mydict: %#",myDict);
NSLog(#"1st: %#",[myDict objectForKey:#"firstQuestion"]);
NSLog(#"2nd: %#",[myDict objectForKey:#"secondQuestion"]);
NSLog(#"3rd: %#",[myDict objectForKey:#"thirdQuestion"]);
}
Class B - Swift:
var questionDelegate: SelectedQuestionDelegate?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
print("selected index :",indexPath.row)
let selectedCell = tableView.cellForRow(at: indexPath)
print("did select and the text is \(selectedCell?.textLabel?.text)")
let storyboard = UIStoryboard(name: "EnrollmentChallengeQuestions", bundle: nil)
challengeVC = storyboard.instantiateViewController(withIdentifier: "ChallengeQuestions") as! EnrollmentChallengeQuestionsViewController
challengeVC.passedValue = selectedCell?.textLabel?.text
print("text label value: ", challengeVC.passedValue)
questionDelegate?.valueChanged(challengeVC.passedValue)
self.present(challengeVC, animated: true , completion: nil)
}
Here in ValueChanged function, My dictionary is holding only one value at a time. I want to hold the first question for first row, second question for second row and for third also simultaneously. My dictionary is getting refreshed each time. Also tried to alloc my dict in viewdidload & viewwillappear. All methods getting called again while coming from another class. How to overcome this issue?
I think you need to use dismiss(animated: true, completion: nil) instead of self.present(challengeVC, animated: true , completion: nil).
Currently when you select a question , you present the challengeVC, again so its viewDidLoad and viewWillAppear methods are being called again, hence your dictionary is being allocated again

iOS 8 custom input view background color

I have a custom input view that I swap out with the iOS keyboard. Previous to iOS 8, for iOS 7 I "sussed out" the keyboard backdrop by finding the subview of class UIKBInputBackdropView (contained by a UIPeripheralHostView). Then I was able to set the alpha of the backdrop view to get a clear custom input view backdrop.
With iOS 8, this no longer works (i realize it is unsupported API and this is the risk). Through some experimentation and reading here, it seems that the custom input view is now found in a view hierarchy as such:
UIInputSetContainerView -> UIInputSetHost
It looks like there is no longer a backdrop view that is providing the opacity behind the custom input view. Can someone point me to how get rid of the translucent/blur effect behind my custom input view?
I had same issue on iOS 8 and there is way to remove background from input view.
- (void)removeKeyboardBackground
{
// Locate non-UIWindow.
UIWindow *keyboardWindow = nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
if (![[testWindow class] isEqual:[UIWindow class]]) {
keyboardWindow = testWindow;
break;
}
}
// Locate background.
for (UIView *possibleFormView in [keyboardWindow subviews]) {
if ([[possibleFormView description] hasPrefix:#"<UIInputSetContainerView"]) {
for (UIView* peripheralView in possibleFormView.subviews) {
if ([[peripheralView description] hasPrefix:#"<UIInputSetHostView"]) {
for (UIView* backSubiview in peripheralView.subviews) {
if ([[backSubiview description] hasPrefix:#"<UIKBInputBackdropView"]) {
[[backSubiview layer] setOpacity:0.0];
}
}
}
}
}
}
}
I used a variant of the accepted answer for later iOS versions. It looks like Apple has pushed the UIKBInputBackdropView under another UIView now:
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:(v) options:NSNumericSearch] != NSOrderedAscending)
- (void)removeKeyboardBackground
{
NSString *viewPath;
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"11.0"))
viewPath = #"UIRemoteKeyboardWindow/UIInputSetContainerView/UIInputSetHostView/UIView/UIKBInputBackdropView";
else
viewPath = #"UIRemoteKeyboardWindow/UIInputSetContainerView/UIInputSetHostView/UIKBInputBackdropView";
NSArray *appWindows = [NSMutableArray arrayWithArray:[[UIApplication sharedApplication] windows]];
NSArray *viewsFound = [self viewsFromViews:appWindows AtPath:[viewPath componentsSeparatedByString:#"/"]];
for (UIView *background in viewsFound)
background.layer.opacity = 0.0;
}
- (NSArray<__kindof UIView *> *)viewsFromViews:(NSArray<__kindof UIView *> *)views AtPath:(NSArray<NSString *> *)path
{
NSMutableArray *viewsFound = [NSMutableArray array];
if (views != nil && path != nil && [views count] > 0 && [path count] > 0)
{
NSString *prefix = [#"<" stringByAppendingString:[path firstObject]];
NSArray *pathRemaining = [path count] <= 1 ? nil : [path subarrayWithRange:NSMakeRange(1, [path count] - 1)];
for (UIView *view in views)
if ([[view description] hasPrefix:prefix]) {
if (pathRemaining == nil)
[viewsFound addObject:view];
else
[viewsFound addObjectsFromArray:[self viewsFromViews:[view subviews] AtPath:pathRemaining]];
}
}
return viewsFound;
}

Moving the cursor once max length is reached

I've crudely put together this code based on some other answers on SO but I still can't get it to work. I want my cursor to move to the next textField once a certain length has been reached, and it does that...to an extent.
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if (textField.tag == 0 && range.location >= 1) {
[_secondTextField becomeFirstResponder];
return YES;
} else if (textField.tag == 1 && range.location >= 2) {
[_thirdTextField becomeFirstResponder];
return YES;
} else if (textField.tag == 2 && range.location >= 1) {
[_fourthTextField becomeFirstResponder];
return YES;
} else {
return YES;
}
}
...
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// catched the delegates for the input textfields
_firstTextField.delegate = self;
_secondTextField.delegate = self;
_thirdTextField.delegate = self;
[_firstTextField becomeFirstResponder];
}
So I have 4 textfields, and I have character limits of 1, 2, and 1 for the first 3 text fields. The problem right now is the cursor will not move to the next textfield until after I type more text. This next text is in the new textfield, so the overall effect is achieved, but the cursor just isn't moving at the right time.
What can I do so that the cursor will move as soon as I reach the character limit?
A better way would be to use the didChange method like the UITextViewDelegate method, but as we know the UITextFieldDelegate does not have a didChange method. You can manually add behaviour. You can use the shouldChangeCharactersInRange: method, but personally I would advise not to override methods unless you absolutely have to.
You can add behaviour using:
[yourTextField addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
And in the target method:
- (void)textFieldDidChange:(UITextField*)textField{
if (textField.tag == 0 && textField.text.length == 1){
[_secondTextField becomeFirstResponder];
}else if (textField.tag == 1 && textField.text.length == 2){
[_thirdTextField becomeFirstResponder];
}else if (textField.tag == 2 && textField.text.length == 1){
[_fourthTextField becomeFirstResponder];
}
}

problem with the if statement

i m parsing a json file.the logic goes like this, if there is no data in the variable named boy.it got to enter the if loop and if there is data it got to enter the else part.but the problem is even if the variable boy is empty(which shows empty in the console) the loop still enters the else part..cud u guys help me out..below is the code..
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
NSDictionary *boy=[url objectAtIndex:indexPath.row];
NSLog(#"the boy value:%#",boy);
if (boy == NULL)
{
Secondetailview *detailViewController1 = [[Secondetailview alloc] initWithItem:boy];
[self.navigationController pushViewController:detailViewController1 animated:YES];
[detailViewController1 release];
}else
{
FirstViewDetail *detailViewController = [[FirstViewDetail alloc] initWithItem:boy];
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
}
}
I would try to use if (boy == nil) but that doesn't seem to work either.
Instead do this:
NSString *str = [NSString stringWithFormat:#"%#", boy];
if ([str isEqualToString:#""]) {
//boy is nil do your stuff
}
Replace
if (boy == NULL)
with
if ([boy count] == 0)
Modify your if condition as below and see if that works.
((boy == NULL) || ([boy count] == 0))