Is there a way I can get an SKLabelNode to change its text property using an SKAction? I would prefer an answer in Swift but one in Objective C will suffice. Thanks
Works using blocks
SKAction *changeTextAction = [SKAction runBlock:^(void){[self.someLabel setText:#"some string"];}];
Then just run the action
[self runAction:changeTextAction];
Related
I have two entities:
Ticket
TicketResolved
Both entities have the same attributes. What would be the the most efficient way to copy a Ticket NSManagedObject to TicketResolved NSManagedObject?
I'm thinking using a Category: Ticket+Copy be the least expensive way? If so, I would have to #import both Ticket and TicketResolved in the Category file.
Here is what I came up with, can someone please advise if this is the right way of going about it. I'm using NSManagedObjectSubclass for each entity.
Method in Ticket+Copy:
-(TicketResolved *)copyObjects:(Ticket *)ticket
{
TicketResolved *ticketResolved = [NSEntityDescription insertNewObjectForEntityForName:#"TicketResolved" inManagedObjectContext:self.managedObjectContext];
ticketResolved.attribute = ticket.attribute;
// Assign rest of the ticketResolved attributes values this way
return ticketResolved;
}
Now calling the Method
#import Ticket;
#import Ticket+Copy;
#implementation
....
Ticket *ticket = [NSEntityDescription insertNewObjectForEntityForName:#"Ticket" inManagedObjectContext:self.managedObjectContext];
TicketResolved *newTicketResolved = [ticket copyObjects:ticket];
// 'newTicketResolved' now has all the keys/values that 'ticket' had.
Is this a right approach or is there a simpler way to do this?
If Ticket and TicketResolved actually have the same attributes, the most efficient option is to:
Get rid of TicketResolved
Add a boolean flag on Ticket named resolved that you can set to YES when the ticket is resolved.
Use this attribute it fetch requests to get either resolved or non-resolved tickets, whichever you need.
Then you don't actually need to copy any data, and not doing work is always more efficient than doing it.
If for some reason you really want two separate entities with the same attributes, basically you have it, you need to create a TicketResolved instance and have your code copy over every attribute value. The only major problem with your code is lines like this:
Ticket *ticket = [Ticket alloc]init];
You can't create managed objects like that, because you're not calling the designated initializer. You need to either use -[NSManagedObject initWithEntity:insertIntoManagedObjectContext:] or else use +[NSEntityDescription insertNewObjectForEntityForName:inManagedObjectContext:].
Thanks to #Tom, I did correct my error in the question.
Below is the solution that worked for me:
TicketResolved *ticketResolved = [NSEntityDescription insertNewObjectForEntityForName:#"TicketResolved" inManagedObjectContext:self.managedObjectContext];
NSArray *keys = [[[ticket entity] attributesByName] allKeys];
NSDictionary *dict= [ticket dictionaryWithValuesForKeys:keys];
[ticketResolved setValuesForKeysWithDictionary:dict];
The code above does not copy the Relationships Objects. For that I had to use the code below:
ticketResolved.relationshipObject = ticket.relationshipObject;
I want to change some or all of the attributed text of a rich UITextView (iOS 6), and allow the user to undo the change.
After reading NSUndoManager documentation, I tried the first way:
“Simple undo” based on a simple selector with a single object argument.
I expected an undo operation to be as simple as:
Declare this method:
- (void)setAttributedStringToTextView:(NSAttributedString *)newAttributedString {
NSAttributedString *currentAttributedString = self.textView.attributedText;
if (! [currentAttributedString isEqualToAttributedString:newAttributedString]) {
[self.textView.undoManager registerUndoWithTarget:self
selector:#selector(setAttributedStringToTextView:)
object:currentAttributedString];
[self.textView.undoManager setActionName:#"Attributed string change"];
[self.textView setAttributedText:newAttributedString];
}
}
Change the text in my UITextView by calling:
[self setAttributedStringToTextView:mutableAttributedString];
But after doing that, NSUndoManager says it cannot undo.
NSLog(#"Can undo: %d", [self.textView.undoManager canUndo]);
// Prints: "Can undo: 0"
So I tried the second way:
“Invocation-based undo” which uses an NSInvocation object.
Declare this:
- (void)setMyTextViewAttributedString:(NSAttributedString *)newAttributedString {
NSAttributedString *currentAttributedString = [self.textView attributedText];
if (! [currentAttributedString isEqualToAttributedString:newAttributedString]) {
[[self.textView.undoManager prepareWithInvocationTarget:self]
setMyTextViewAttributedString:currentAttributedString];
[self.textView.undoManager setActionName:#"Attributed string change"];
[self.textView setAttributedText:newAttributedString];
}
}
and change the text with:
[self setMyTextViewAttributedString:mutableAttributedString];
After that, NSUndoManager also says it cannot undo.
Why?
Note that the user is editing the UITextView when triggering the code that will change the attributed text.
A workaround would be to replace the text directly via UITextInput protocol method. The following method is quite convenient, but I haven't found an equivalent for NSAttributedString. Did I miss it?
- (void)replaceRange:(UITextRange *)range withText:(NSString *)text
An hack suggested here is to simulate a paste operation. If possible, I would prefer to avoid this (no reason yet, just feels too dirty to not come back bite me later).
I'm kinda still in shock this works. I posted the same answer over here UITextView undo manager do not work with replacement attributed string (iOS 6).
- (void)applyAttributesToSelection:(NSDictionary*)attributes {
UITextView *textView = self.contentCell.textView;
NSRange selectedRange = textView.selectedRange;
UITextRange *selectedTextRange = textView.selectedTextRange;
NSAttributedString *selectedText = [textView.textStorage attributedSubstringFromRange:selectedRange];
[textView.undoManager beginUndoGrouping];
[textView replaceRange:selectedTextRange withText:selectedText.string];
[textView.textStorage addAttributes:attributes range:selectedRange];
[textView.undoManager endUndoGrouping];
[textView setTypingAttributes:attributes];
}
I have a weird problem with FetchRequest template.
When i explicitly hardcode the variable I wish to substitute:
NSFetchRequest *fetchRequest = [[[Helper appDelegate] managedObjectModel]
fetchRequestFromTemplateWithName:#"srStoryForLesson"
substitutionVariables:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:2] forKey:#"number"]];
Every thing works fine.
But When I try to set a var as the Integer (as i want it to be dynamic) I get no results from the fetch.
NSInteger number = 2;
NSFetchRequest *fetchRequest = [[[Helper appDelegate] managedObjectModel]
fetchRequestFromTemplateWithName:#"srStoryForLesson"
substitutionVariables:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:number] forKey:#"number"]];
I can not understand what is wrong?
Thanks
Shani
The code you show should work fine. Your error is elsewhere.
I would recommend not using variable names like "number" because their generic nature risk naming collisions in Objective-C's global name space. A more unique and descriptive name is safer and easier to read months down the road when you revisit the code.
I have NSDictionaries stored in an NSMutableArray. Each NSDictionary has a NSNumber inside of it. So right now, my tableview will show the cells in the way they are ordered in the array. What I want to do is reorder the cells from highest NSNumber to lowest NSNumber, so how would I do this with all the NSDictionaries in the NSMutableArray. I will probably need a for loop or something like that but I am not sure how to do it.
Also I have NSDate's (non-formatted) in my NSDictionaries, so how would I sort the NSDictionaries based upon the newest dates inside them?
Thanks!
You need to use the sortedArrayUsingSelector method of NSMutableArray and provide a sorting function, like this:
NSMutableArray *yourSortedArray;
yourSortedArray = [originalArray sortedArrayUsingSelector:#selector(yourCompareFunction:)];
...
- (NSComparisonResult)yourCompareFunction:(NSDictionary *)otherObject {
return [[self objectForKey:#"number_key"] compare:[otherObject objectForKey:#"number_key"]];
}
I didn't tested this but that's the idea.
Here is my array:
MyTestArray=[NSMutableArray arrayWithObjects:#"Who invented america?",#"Fredrick",#"Colob bas",#"Alfred Novel",#"Sohel",nil];
I want to print it as follows :
NSLog(#"%#",[MyTestArray objectAtIndex:0]);
What i did wrong here?I just wanted to get value at the index.But my program is crashing here.:(
Just to check. what is the variable MyTestArray declared as? It should be declared as NSMutableArray.
UPDATED:
This is a memory problem. Are you retaining your MyTestArray? arrayWithObjects: method return an autorelease object. So it might only be valid for the current loop and being released when the next loop begin.
There's several way to retain object. I always recommend using property but for you it can be as simple as doing this.
MyTestArray = [[NSMutableArray arrayWithObjects:#"Who invented america?",#"Fredrick",#"Colob bas",#"Alfred Novel",#"Sohel",nil] retain];
Shouldn't crash now.