I've got a bizarre question that I've been researching/playing with for hours now.
I'm working on a simple note-taking app, storing notes in an NSMutableDictionary with the Key as the title and the Value as the note. I've got a delegate function that saves the contents of an NSTextView each time it changes.
-(void)textDidChange:(NSNotification *)notification {
NSString *currentNote = [_mainTextField string];
[Data setNote:currentNote forKey:currentKey];
}
and then adds it to the Dictionary.
+(void)setNote:(NSString *)note forKey:(NSString *)key {
[allNotes setObject:note forKey:key];
}
while currentKey is a global variable that is updated elsewhere (and which I have tested thoroughly and is working fine).
Here's where it gets weird: You'd expect the Dictionary to update a single Key for each call of setNote:forKey: as long as the Keys are all unique (which they are). But instead, it's updating all previously-updated Keys each time. So if you had a Dictionary like this.
"John" = "apples";
"David" = "apples";
and you updated "John" to "bananas"
"John" = "bananas";
"David" = "apples";
and then you updated "David" to "oranges", you'd get this:
"John" = "oranges";
"David" = "oranges";
I've breakpoint'd and NSLog'd the hell out of it, and what I've discovered is that "John" changes to "oranges" by the beginning of the setNote:forKey: method, before the [allNotes setObject:note forKey:key] line is even called. Now, that's the only place in my entire program that changes the allNotes Dictionary, but somehow the original row is being re-changed before the function is even called. The first time you make a change (the "bananas" round) everything works perfectly regardless of the size of the Dictionary or which entry is being changed, and the second time (the "oranges" round) it all works perfectly again, except for changing the previously-changed rows as well.
I don't know how to get any more exact with the cause in my code, since the exact instant a key is pressed, textDidChange: gets called and by that point the first entry has already been altered. And notably, when I stop the app and re-run, it goes back to changing the first one normally, and begins the whole thing again.
The other weird part is, the Key variables are working fine. I've checked in the debugger: both the global variable currentKey and the local variable key derived from it will be "David", and yet the changes will affect both "David" and "John", and any others changed before "John" as well. How could it even know what lines were previously edited, with only the current Key value to work with?
I am admittedly a Cocoa beginner, but I am absolutely stumped. Can anyone shed any light on this for me?
When a key/value pair is added to a dictionary the key is copied while the value is retained. Keys are copied so they cannot be changed - the internal organisation of the dictionary is based on the keys.
The values are retained as they must continue to exist while in the dictionary, but if the value is a mutable type then it is OK for it to be mutated. E.g. If you create a dictionary of NSTextField objects then the association between keys and NSTextField objects is fixed, but the contents of the individual text fields themselves can change.
It looks like that in your code [_mainTextField string] is returning a reference to the same NSMutableString object each time it is called. This would mean that every value in your dictionary is a reference to the same mutable object and give you the behaviour you are seeing. You can address this by either changing [_mainTextField string] to return an NSString by copying the mutable string it is using internally; or by copying what is returned using [[_mainTextField string] copy]. The former is better if the purpose of [_mainTextField string] is to return a snapshot of the current value of _mainTextField (whatever its type is - the sample does not say).
Related
Currently I have a view like new feed of facebook where post by users listed in time order. Now on the right hand side I want to put the Alphabetical scroll bar and when user scroll to any character, they can search post by users with name start by that character, is it possible though ?
For my understanding, it could be solve if I can capture the event when user scroll to each character and transfer that character to API on server to query the DB with names start with that and post it back to display on device.
Could any one give me some hint please !
What you want to do is a quite unusual type of user interface, but if you really want to do this, you could do the following (you can find a tutorial here):
In your tableViewController, create an index array, e.g. an array of alphabetic characters that you want to be displayed at the side of your tableView, e.g.:
- (NSArray *)sectionIndexTitlesForTableView:(UITableView *)tableView {
NSARRAY *characters = #[#" ", "A", #"B", #"C", #"D", #"E", #"F", #"G", #"H", #"I", #"J", #"K", #"L", #"M", #"N", #"O", #"P", #"Q", #"R", #"S", #"T", #"U", #"V", #"W", #"X", #"Y", #"Z"];
return characters;
}
According to the docs: „An array of strings that serve as the title of sections in the table view and appear in the index list on the right side of the table view. The table view must be in the plain style (UITableViewStylePlain). For example, for an alphabetized list, you could return an array containing strings “A” through “Z”.“
It is completely up to you, how you sort your data into the sections of the tableView. In your case, you want to have all time sorted data in one section, probably without a special header. Therefore your array characters starts with a header #" " at index 0, and you put all of your time sorted entries in section 0.
Then, implement the following method:
- (NSInteger)tableView:(UITableView *)tableView
sectionForSectionIndexTitle:(NSString *)title
atIndex:(NSInteger)tappedIndex {
self.savedTappedIndex = tappedIndex;
return 0;
}
This method may be a bit confusing. It does the following: When the user taps at the index on the side of your tableView (#" " … #"Z") a certain character in the array characters, the position of this character in the array (its index) is input to this method. You can store it in a property. If you return 0 like in the example, section 0 of the table would be redisplayed as it is.
If you do key value observation (KVO) of the property savedTappedIndex, you will get a notification when the table is redisplayed. You can then read the tapped character by
NSString *tappedCharacter = characters[self.savedTappedIndex];
With this character, you can question your server for feeds, which were created by users whose name starts with this character.
The data can then be displayed in the tableView, again in section 0.
Of course, you should then no longer display the index at the side of the tableView.
Once again, this behavior may be very confusing to the user, since it is quite unusual.
Final note:
You should not use the hack above for a real implementation, but you could use it to test your user interface, and you will probably see that the user experience is not good, since the index behaves differently as usual.
I've been writing an app that involves using NSUserDefaults to store a few Int variables and it's been working fine. I thought I was finished and was doing some final testing and one of the first lines of code that I wrote, and that has been working consistently before, has failed me.
Apparently the green line error is supposed to occur if I try to unwrap an optional that has a value of nil, but this variable is still very much an optional
var savedTotalSeconds: Int? = userDefaults.objectForKey("totalSecondsKey") as Int?
Why would this possibly return an error? It was working fine before and I only changed things I thought were unrelated to it. In the app I have a button to remove this stored value via:
userDefaults.removeObjectForKey("totalSecondsKey")
What could possibly have gone wrong?
Try using 'as? Int' instead of 'as Int?'
The difference is that the first one tries, and might fail, at casting to Int. That failure will be captured in the optionality of the resulting variable.
The second one tries to coerce the object to 'Int?'.
Thanks To all that helped problem solved. :)
For some reason this wont work for me please help
array = [[NSMutableArray alloc] init];
inputted = [input.text doubleValue];
[array addObject:[NSNumber numberWithDouble:inputted]];
NSLog(#"%i",array.count);
where array is a NSMutableArray, inputted is a double and input is a text field
All that happens is that one saves but deletes the last one entered. how do i make it so that it saves everything entered?
You're always re-creating and re-initializing the "array" mutable array each time you go through your function so it's no wonder you are getting a result of "1" (one object in the array).
If you initialize your array once and only once, and move it out and away from the rest of that code (i.e. into a different function or whatever), then you will add additional objects to your mutable array and you'll see the count increment each time you add an object to your mutable array.
Makes sense?
So I have an NSDictionary that contains several objects with properties (key:values), but the issue is that I need them in a specific order.
Stored as an NSArray is a list of objects that I would like to use as keys for the NSDictionary.
I can output the NSArray and NSDictionary to the Console, however when I to access each of the values keyed to "filename" with:
for(NSUInteger i=0; i<[images count]; i++)
NSLog(#"%#", [[dictionary objectForKey:[images objectAtIndex:i]] objectForKey:#"filename"]);
I get all nulls.
Anyone have any idea? I'm assuming it's because my [images objectAtIndex:i] returns something other than a string, however I've tried slappin in a (NSString *) and I still get nulls.
If the things in the dictionary aren't dictionaries, shouldn't that second objectForKey be valueForKey?
NSLog(#"%#", [[dictionary objectForKey:[images objectAtIndex:i]] objectForKey:#"filename"]);
I get all nulls.
Getting the key from the array is working fine. Either dictionary does not have an object for the key you retrieved, or the dictionary you retrieved does not have an object for the key #"filename".
I'm assuming it's because my [images objectAtIndex:i] returns something other than a string, however I've tried slappin in a (NSString *) and I still get nulls.
First, NSStrings are not the only valid keys. Any copyable object is usable as a dictionary key.
More importantly, remember that you never work directly with object structures, but with pointers to objects. objectAtIndex: returns a pointer to an object; when you cast its return value, you're telling the compiler that objectAtIndex: will return a pointer to an NSString object. Casting a pointer does not change the pointer itself; it only tells the compiler what to expect at the other end of that pointer. If objectAtIndex: is returning pointers to, say, Foo objects, casting them to pointers to NSString objects will not make them point to NSString objects; they will still point to Foo objects, so looking those objects up in a dictionary whose keys are strings will still fail.
The other thing to consider is: Why don't you know what is in this array? You created the array. You populated the array. Surely, then, you should know what's in it. objectAtIndex: does not return anything but (a pointer to) an object that is in the array.
If you think objectAtIndex: is returning objects that are not valid keys, then you should examine the array using either NSLog or the debugger. Check what the array contains and what those objects' classes are.
More probably, the array does contain objects that would be valid as keys, but are not keys in the dictionary, or it does contain objects that are keys in the dictionary, but the dictionaries that are the objects for those keys do not contain the #"filename" key. Examine both the array and the outer dictionary.
One other caveat, which may be what's tripping you up: If you're keeping mutable strings in the array, and those are the keys you initially inserted dictionaries into the outer dictionary under, and you mutate these strings, that makes them not match the keys in the outer dictionary. Remember that dictionaries copy their keys (this is why keys need to be copyable); you mutate the string you have in the array, but the dictionary made a copy previously, and that copy does not change. (Such is the point of making a copy: Whoever makes the copy—in this case, the dictionary—wants to keep the object as it is, without receiving any mutations that occur later on.)
So, if you want to revise any of the strings, you'll have to replace them in the array and store the outer dictionary's object for the old key under the new key. You'll also have to take steps to prevent duplicate keys; the dictionary only holds one object per key, while the array can contain the same object any number of times.
A note item in Yojimbo's Applescript dictionary is defined as:
note item n [inh. database item] : A note item.
elements
contained by application.
properties
encrypted (boolean, r/o) : Is the note is encrypted?
contents (text) : The contents of the note. syn content
If this note is encrypted, the contents property is only readable
if permitted by the current security policies.
responds to
append, prepend.
In an attempt to export my data, I've been poking around with AppleScript, learning the language, etc, and currently have this:
tell application "Yojimbo"
repeat with EachNote in (note items in library)
display dialog (content of EachNote) as string
end repeat
end tell
What's confusing me is that, though the class defines the property "contents", I have to use "content" to retrieve the contents. Using "contents" results in this error:
Can’t make «class YNot» id "A0C9E19E-3106-44F9-97A6-A1A74AD77948"
of application "Yojimbo" into type string.
I'm assuming the "syn content" means it's a synonym, thus I should be able to use "content" and "contents" interchangeably. But apparently the synonym works, but the original does not...?
Also, more simply, why do the contents have to be coerced into a string? If I look at the properties on the object (via: (properties of EachNote) as string ), "contents" is a double-quoted string, though I realize this isn't necessarily "proof" that it's a string.
I'm still starting with AppleScript, so if I'm making a n00bish mistake, feel free to slap.
For others who find a similar confusion, I found help here: http://groups.google.com/group/yojimbo-talk/browse_thread/thread/d04f42db335c77e7
So all props go to Jim for being awesome!
The basics:
contents of an object is different than contents of a variable containing an object.
contents of a variable containing an object returns the object, not the object's contents, unlike every other property. Other properties return the property of the object in the variable, as expected.
This means, to get the contents of an object inside a variable, you need to use contents of contents of variable.
As demonstrated here, on my blog, yes, this is extremely strange. While var == var and var == contents of var, var != contents of (contents of var), so Applescript does indeed violate the identity principle for "contents" in this specific case. It does not chain this effect, though, so you shouldn't need to use contents of three layers deep (it'll work the same as two)
contents of contents of var works on objects as well, so it's always safe to use.
Many dictionaries use content as a synonym of contents, which avoids this whole problem. If desired, use content of var, and it'll work like other properties, always returning the object's content instead of the object.