Update Data of a parent by his child - ios

Sorry if the title is not really clear, I will explain it here anyway.
I've got 2 files: SelectPostIt.xib and PostIt.xib .
On my main.storyboard i've got a UIButton which, when someone push it, it create a new SelectPostIt. This one is non editable.
The principle is that when I doubleTap a selectPostIt, a new PostIt appears:
-(IBAction)doubleTap:(UITapGestureRecognizer *)recognizer {
if(!_isEdited){
_isEdited = true;
PostIt *editPostIt = nil;
NSArray *objects = [[NSBundle mainBundle] loadNibNamed:#"PostIt" owner:self options:nil];
for (id object in objects)
{
if ([object isKindOfClass:[PostIt class]])
{
editPostIt = object;
}
}
editPostIt.frame = CGRectMake(10,10, 400, 400);
[editPostIt setParent:self];
[self.superview addSubview:editPostIt];
}}
So normally, the selectPostIt is seated as Parent of the the new Post it in: [editPostIt setParent:self]; , right? I already have (in PostIt.m):
-(void)setParent:(SelectPostIt*)value{
_parent = value;
}
With a property(weak, nonatomic) SelectPostIt* parent;in my PostIt.h.
And then, when I double tap on the PostIt, it will disappear but also change the value of the SelectPostIt who created him with this method:
-(IBAction)doubleTap:(UITapGestureRecognizer *)recognizer{
NSString *string = [self.titre text];
//NSLog(#"string: %#", string );
[_parent setTitre:string];
string = [self.commentaire text];
//NSLog(#"string: %#", stringFromTextField );
[_parent setCommentaire:string];
[_parent setIsEdited:true];
if(_parent == NULL)
NSLog(#"Pas de parents" );
if(_parent == nil)
NSLog(#"Pas de parents" );
[self removeFromSuperview];
}
I made some test and the String are good but, the value of the SelectPostIt aren't changed (the good point is that the PostIt disappear at least haha).
So if someone could help me on where I am wrong it could be nice, thanks in advance :)

That's not the exact answer but that's a point I think I must dig on:
I've added in my PostIt.m:
#synthesize parent;
And changed :
[parent setIsEdited:true]
To : (that was a mistake from me here)
[parent setIsEdited:false]
So now, my PostIt.m 's doubleTap method looks like:
-(IBAction)doubleTap:(UITapGestureRecognizer *)recognizer{
NSString *string = [self.titre text];
[parent setTitre:string];
string = [self.commentaire text];
[parent setCommentaire:string];
[parent setIsEdited:false];
[self removeFromSuperview]; }
And from now, when I close a editPostIt , when I doubleTap on the selectPostIt a new editPostIt is created, and I wasn't able to before. That's mean that the boolean from the selectPostIt has been changed by the closure of the editPostIt .
So I think from now that, this is good:
-(IBAction)doubleTap:(UITapGestureRecognizer *)recognizer{
NSString *string = [self.titre text];
[parent setTitre:string];
string = [self.commentaire text];
[parent setCommentaire:string];
[parent setIsEdited:false];
[self removeFromSuperview]; }
But I need to "reload" (?) the selectPostIt or something else so it could take the new data? I dont really know...

Related

How to pass value in uitextview using segue

I'm trying to create something in UITextView that every time the text encounter this kind of symbol "#". All text after that symbol will send to other controller.
here's my code
- (BOOL)textView:(UITextView *)aTextView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
// "Length of existing text" - "Length of replaced text" + "Length of replacement text"
NSInteger newTextLength = [self.addingText.text length] - range.length + [text length];
if([text isEqualToString:#"#"] || secondString){
secondString = true;
NSString * stringToRange = [self.addingText.text substringWithRange:NSMakeRange(0,range.location)];
// Appending the currently typed charactor
stringToRange = [stringToRange stringByAppendingString:text];
// Processing the last typed word
NSArray *wordArray = [stringToRange componentsSeparatedByString:#"#"];
self.getSecondString = [wordArray lastObject];
// wordTyped will give you the last typed object
NSLog(#"\nWordTyped : %#",self.getSecondString);
}
if (newTextLength > 50) {
// don't allow change
[aTextView resignFirstResponder];
return NO;
}
self.countChar.text = [NSString stringWithFormat:#"%li", (long)newTextLength];
return YES;
}
I get that code from here. It is perfectly work when I use NSLog but the time I click the button to send it to other controller using segue. It always show Null value. Hoping your help here. Thanks in advance
here's my button code
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
CameraViewController * cameraViewController = (CameraViewController *)[segue destinationViewController];
if([segue.identifier isEqualToString:#"createText"]){
NSLog(#"prepareForSegue: %# == %#", self.addingText.text,self.getSecondString);
cameraViewController.inputCreateText = [NSString stringWithFormat:#"%#", self.addingText.text];
cameraViewController.secondInputCreateText =[NSString stringWithFormat:#"%#", self.getSecondString];
}
}
I think your problem is you are modifying your string inside textView:shouldChangeTextInRange: which gets called for every typed in character. If your purpose is to send the string after # on tap on a button then do the calculation on button handler or inside prepareForSegue:sender:. If for some reason you want to stick to your own implementation then I would advise to put your targeted string inside NSMutableArray property created at class level so you don't loose data. And then you can combine all string inside that array like this [arrayOfStrings componentsJoinedByString:#" "].

Expected Identifier

Please can anyone tell me why this piece of code isn't working? I've got a dictionary which contains UIViews with tables inside associated with the keys which are the names of the corresponding buttons (there are a lot of them). So what I actually want to do is to change the view visibility on the corresponding button click. But the issue is that the expression to do that is not accepted by Xcode and I get the Expected Identifier error.
- (IBAction)choosingButtonClicked:(id)sender {
if ([sender currentTitle]) {
[(UIView *)[self.selectionTables objectForKey:[sender currentTitle]]].hidden = ![(UIView *)[self.selectionTables objectForKey:[sender currentTitle]]].isHidden;
}
}
First of all, with all due respect, I agree with trojanfoe comments. Its not working because its not properly written.
Now, lets try to streamline it with below code:
- (IBAction)choosingButtonClicked:(id)sender {
NSString *title = [sender currentTitle];
if (title) {
UIView *selectionView = (UIView *)self.selectionTables[title];
selectionView.hidden = !selectionView.isHidden;
}
}
Your code is too complex, because of that even the author can't understand it. If we re-write your code using local variables, it will look like:
- (IBAction)choosingButtonClicked:(id)sender
{
NSString *title = [sender currentTitle];
if (title)
{
UIView *tempView = (UIView *)[self.selectionTables objectForKey:title];
[tempView].hidden = ![tempView].isHidden;
}
}
If you check the code now, you can see that the following code is causing the issues:
[tempView].hidden = ![tempView].isHidden;
Change your method like:
- (IBAction)choosingButtonClicked:(id)sender
{
NSString *title = [sender currentTitle];
if (title)
{
UIView *tempView = (UIView *)[self.selectionTables objectForKey:title];
tempView.hidden = !(tempView.isHidden);
}
}

My UILabel is not displaying when my if statement is false

I have a story board that has a UITextField, UIButton, UIImage, and UILabel to display the images in an array. If you type the correct name for the image file into a text field. So, the problem is that once the text field input does not match, it should update the UILabel to display "Result not found", but it doesn't.
#import "ViewController.h"
#interface ViewController ()
{
myClass *myNewClass;
NSMutableArray *picArray;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
picArray = [#[#"Button_Red",#"Button_Green"]mutableCopy];
}
- (IBAction)displayImageAction:(id)sender
{
NSString *titleSearched = self.textSearchField.text;
NSString *titleNotHere = self.notFoundLabel.text;
//Declare a bool variable here and set
BOOL variable1;
for (int i = 0; i < picArray.count; i++)
{
NSString *currentPic = picArray[i];
if ([titleSearched isEqualToString:currentPic])
{
variable1 = YES;
}
}
if (variable1 == YES) {
//this works fine displays the image
self.outputImage.image = [UIImage imageNamed: titleSearched];
[self.textSearchField resignFirstResponder];
} else {
//problem is here its not showing when input for the array is not equal it should display a message label "Result Not Found" but it remains blank on the IOS simulator
titleNotHere = [NSString stringWithFormat:#"Result Not found"];
[self.textSearchField resignFirstResponder];
}
}
//Get rid of the texfield when done typing
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Retract keyboard if up
[self.textSearchField resignFirstResponder];
}
Your problem is that
titleNotHere = [NSString stringWithFormat:#"Result Not found"];
simply sets the method variable titleNotHere.
What you want is
self.notFoundLabel.text=#"Result Not found";
You will also want
self.notFoundLabel.text=#"";
when the result is found.
I think you will have to SET the value to the variable
self.notFoundLabel.text = [NSString stringWithFormat:#"Result Not found"]
or
self.notFoundLabel setText:[NSString stringWithFormat:#"Result Not found"]
UILabel.text = #"whatever..." is actually converted into [UILable setText:#"whatever..."].
NSString *labelText = UILabel.text has to be thought as NSString *labelText = [UILabel text];
This:
NSString *titleNotHere = self.notFoundLabel.text;
stores the text from the label into a variable, but updating that variable again will not change the label text - it only changes what that variable points to.
You need to explicitly update the label text:
self.notFoundLabel.text = #"Result Not found";
note also that this uses a string literal - you don't need to use a format string as you aren't adding any parameters to it.
Also, when checking booleans, don't use if (variable1 == YES) {, just use if (variable1) { (it's safer).

UITextView textViewDidChangeSelection called twice

What I have :
TextView
NSArray (string)
AVAudioplayer (not yet implemented)
When I select a word in TextView :
• Check if word exist in Array
• Start Audioplayer with associated sound
Unfortunately when I tap twice to select a word inside TextView, textViewDidChangeSelection is called twice. I don’t know why I see "Youpie" twice.
I just changed inputView to hide keyboard because I only need TextView to be used in selecting mode.
- (void)textViewDidChangeSelection:(UITextView *)tve;
{
NSString *selectedText = [tve textInRange:tve.selectedTextRange];
if(selectedText.length > 0)
{
for (NSString *text in textArray)
{
if ([selectedText isEqualToString:text])
NSLog(#"Youpie");
tve.selectedTextRange = nil;
if (ps1.playing == YES)
{
[self stopEveryPlayer];
[self updateViewForPlayerState:ps1];
}
else if ([ps1 play])
{
[self updateViewForPlayerState:ps1];
fileName.text = [NSString stringWithFormat: #"%# (%d ch.)", [[ps1.url relativePath] lastPathComponent], ps1.numberOfChannels, nil];
}
else
NSLog(#"Could not play %#\n", ps1.url);
break;
}
}
}
}
- (void)awakeFromNib
{
textArray = [[NSArray alloc] initWithObjects:#"dog",#"cat",#"person",#"bird",#"mouse", nil];
textView.inputView = [[[UIView alloc] initWithFrame:CGRectZero] autorelease];
textView.delegate = self;
// ...
}
I noticed something when I was double tapping on each good word in my text.
textViewDidChangeSelection
If a word is already selected and no action choosen, I have 1 "Youpie".
If not, I have 2 "Youpie".
I found a simple solution. I removed selectedRange after getting value. textViewDidChangeSelection called once.
What I have changed
tve.selectedTextRange = nil;
I use a subclass of UITextView to disable menu.
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
return NO;
return [super canPerformAction:action withSender:sender];
}
I added an implementation for AVAudioPlayer (ps1) too.
My "autoplay" is working if a known word is selecting :)
I don't have an answer for why the method gets called twice or how to prevent this, but an alternative solution might be to display an additional item in the edit menu that pops up in a text view when a word is double clicked. Then, your action for initiating a sound based on the word could be triggered from the action selector defined in that additional menu item. In this design, you'd remove your textViewDidChangeSelection and thus would not get called twice. See http://developer.apple.com/library/ios/#documentation/StringsTextFonts/Conceptual/TextAndWebiPhoneOS/AddingCustomEditMenuItems/AddingCustomEditMenuItems.html for some additional info about modifying the standard menu.

IOS UIMenuController UIMenuItem, how to determine item selected with generic selector method

With the following setup
....
MyUIMenuItem *someAction = [[MyUIMenuItem alloc]initWithTitle : #"Something" action : #selector(menuItemSelected:)];
MyUIMenuItem *someAction2 = [[MyUIMenuItem alloc]initWithTitle : #"Something2" action : #selector(menuItemSelected:)];
....
- (IBAction) menuItemSelected : (id) sender
{
UIMenuController *mmi = (UIMenuController*) sender;
}
How to figure out which menu item was selected.
And don't say that you need to have two methods... Thanks in advance.
Okay, I've solved this one. The solution isn't pretty, and the better option is "Apple fixes the problem", but this at least works.
First of all, prefix your UIMenuItem action selectors with "magic_". And don't make corresponding methods. (If you can do that, then you don't need this solution anyway).
I'm building my UIMenuItems thus:
NSArray *buttons = [NSArray arrayWithObjects:#"some", #"random", #"stuff", nil];
NSMutableArray *menuItems = [NSMutableArray array];
for (NSString *buttonText in buttons) {
NSString *sel = [NSString stringWithFormat:#"magic_%#", buttonText];
[menuItems addObject:[[UIMenuItem alloc]
initWithTitle:buttonText
action:NSSelectorFromString(sel)]];
}
[UIMenuController sharedMenuController].menuItems = menuItems;
Now your class that catches the button tap messages needs a few additions. (In my case the class is a subclass of UITextField. Yours might be something else.)
First up, the method that we've all been wanting to have but that didn't exist:
- (void)tappedMenuItem:(NSString *)buttonText {
NSLog(#"They tapped '%#'", buttonText);
}
Then the methods that make it possible:
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
NSString *sel = NSStringFromSelector(action);
NSRange match = [sel rangeOfString:#"magic_"];
if (match.location == 0) {
return YES;
}
return NO;
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
if ([super methodSignatureForSelector:sel]) {
return [super methodSignatureForSelector:sel];
}
return [super methodSignatureForSelector:#selector(tappedMenuItem:)];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
NSString *sel = NSStringFromSelector([invocation selector]);
NSRange match = [sel rangeOfString:#"magic_"];
if (match.location == 0) {
[self tappedMenuItem:[sel substringFromIndex:6]];
} else {
[super forwardInvocation:invocation];
}
}
One would expect that the action associated with a given menu item would include a sender parameter that should point to the chosen menu item. Then you could simply examine the title of the item, or do as kforkarim suggests and subclass UIMenuItem to include a proeprty that you can use to identify the item. Unfortunately, according to this SO question, the sender parameter is always nil. That question is over a year old, so things may have changed -- take a look at what you get in that parameter.
Alternately, it looks like you'll need to a different action for each menu item. Of course, you could set it up so that all your actions call a common method, and if they all do something very similar that might make sense.
Turns out it's possible to obtain the UIButton object (which is actually UICalloutBarButton) that represents UIMenuItem if you subclass UIApplication and reimplement -sendAction:to:from:forEvent:. Although only -flash selector goes through UIApplication, it's enough.
#interface MyApplication : UIApplication
#end
#implementation MyApplication
- (BOOL)sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event
{
// target == sender condition is just an additional one
if (action == #selector(flash) && target == sender && [target isKindOfClass:NSClassFromString(#"UICalloutBarButton")]) {
NSLog(#"pressed menu item title: %#", [(UIButton *)target titleLabel].text);
}
return [super sendAction:action to:target from:sender forEvent:event];
}
#end
You can save target (or any data you need from it) in e.g. property and access it later from your UIMenuItem's action.
And to make your UIApplication subclass work, you must pass its name as a third parameter to UIApplicationMain():
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, NSStringFromClass([MyApplication class]), NSStringFromClass([YOUR_APP_DELEGATE class]));
}
}
This solution works on iOS 5.x-7.0 as of post date (didn't test on older versions).
ort11, you might want to create a property of myuimenuitem and set some sort of Tag. Thay way the object of sender could be recognized by its tag it. In Ibaction then you can set a switch statement that can correspond to each sender.tag and work throught that logic. I guess thats the simplest way to go.

Resources