I have dozens of NSStrimgs that when the app loads I want to all be set to the same set. All of them. How can I do this without typing out every single one? Is there a shortcut method?
Thanks.
Also the problem is that Josh isn't specific enough about how he's using his dozens of strings... I think this would be better:
NSMutableArray *stringsArray = [NSMutableArray arrayWithCapacity:1];
NSString *tempStr = #"My unique string"; // Thanks Sven!
// Say you want a dozen strings
for (int i = 0; i < 12; i ++) {
[stringsArray addObject:tempStr];
}
// Now you can use them by accessing the array
[self doSomethingWithString:[stringsArray objectAtIndex:8]];
Instead of having dozens of strings that have the same value, could you make a single static global string and reference that? If you need to change it to separate values later, use instance variables that are initialized to the global string.
This sounds like your model is not very good at all. Since you want to initialize all of your strings to the same value they are obviously related and probably should be modeled as an array like iPhoneDevProf described. That makes other things a lot easier too, you can move other code that is repeated for every string into a loop.
If the value is known when you are compiling the code AND it is not going to change after subsequent application sessions then you can use a simple #define.
#define MY_DEFAULT_STRING #"THE DEFAULT STRING"
Now all you have to do is the following.
{
NSString *myString1 = MY_DEFAULT_STRING;
NSString *myString2 = MY_DEFAULT_STRING;
....
NSString *myStringN = MY_DEFAULT_STRING;
}
If all the strings are in the same code file, just put the define at the top. If the strings are in separate code files, then it could be put into your precompiled header. Having a constants file is usually better.
Using constant extern NSString would probably be more correct, but this is simple and easy to do.
Related
I'm programming a game that has 40 levels and I'm storing all my level data in a .plist. This works great but now that I'm trying to implement multiple levels, I'm looking for a way to call a property on a singleton based on level without manually coding something like a switch/case. I would like to do something like the following:
This is the code I use to pull my data but as you can see, I've hard coded the "dictionaryLevel1Data" property.
int capacity = [[sharedDataManager.dictionaryLevel1Data objectForKey:#"typeWarrior"] intValue];
I would like to set a variable and have the property of the singleton called based on that like this which I know doesn't work. Notice how I'm replacing "dictionaryLevel1Data"
NSString level = #"1";
int capacity = [[sharedDataManager.[NSString stringWithFormat:#"dictionaryLevel%#Data", level] objectForKey:#"typeWarrior"] intValue];
Any suggestions on how I could accomplish this would be greatly appreciated. I can always go and manually setup a switch/case for each level but with 40 levels and 50+ different object types per level it would be rough, it seems like there must be a better way. I hate hard coding values and like to simplify my code with easy updates to variables that run through generic classes and methods.
why don't you do like this;
use 2 level data map;
//sharedDataManager.levelData is a NSDictionary that contains lots of NSDictionarys
NSDictionary *levelData = [sharedDataManager.levelData objectForKey:[NSString stringWithFormat:#"dictionaryLevel%#Data", level]];
int capacity = [levelData objectForKey:#"typeWarrior"] intValue];
If you want do it this way, then you can use Key-Value-Coding, to get a property value from a string. The accepted answer in this post shows how to use it (very easy): Objective-C get a class property from string
For your task it would look something like this:
int capacity = [[[sharedDataManager valueForKey:[NSString stringWithFormat:#"dictionaryLevel%#Data", level]] objectForKey:#"typeWarrior"] intValue];
You can use :
NSString level = #"dictionaryLevel1Data"
SEL methodSelector = NSSelectorFromString(level);
if ([sharedDataManager conformsToSelector:#selector(methodSelector)]) {
NSDictionary *levelData = [sharedDataManager performSelector:methodSelector];
// Do whatever you need here
}
I assume all dictionaryLevelData are synthesized and have getters as their name.
(Note that I did not compile it but it should work)
If I have this code, why doesn't the textview's text update? As far as I knew a * meant a pointer, and I haven't done a copy.
NSString *searchText = myTextView.text;
searchText = [searchText stringByReplacingOccurrencesOfString:#" " withString:#";"];
So why isn't myTextView's text changed as if I did:
myTextView.text = [searchText stringByReplacingOccurrencesOfString:#" " withString:#";"];
And how would I write the code, so that the first code example works as I intend?
The method stringByReplacing... Doesn't change the string, it returns a new string object (autoreleased, according to the naming conventions). So after the 2nd line of code, searchText points to a totally differen NSString object.
Besides, NSString objects cannot be changed, for that there's NSMutableString
If you expect to modify myTextView.text, you have to write it like your second example, and assign a new value to the property you're trying to modify. Assigning a new value to some other variable or property won't do the job - "spooky action at a distance" may work when we eventually have quantum computing, but we're not there yet. :-)
To expand a bit: Yes, searchText is a pointer. But so is myTextView.text, and when you do "searchText = myTextView.text", you're not creating any sort of lasting relationship between the two - all you're doing is making searchText point to the same target as myTextView.text. Changing either one of them after that point will have no effect on the other. So, when you assign the result of stringByReplacing... to searchText, you're making it and only it point to a different target.
Your second example invokes the setter of the "text" property.
Your first example takes the pointer of the string, and then changes the pointer within the same scope. Hence, "text" is not changed.
BTW: Depending on how your property is defined, the setter you use will either copy, retain or assign the value you give the setter. So if you use the following:
#property(copy) NSString* text;
Then yes, the setter will copy the value you give it when you invoke:
myTextArea.text = //some string
OK, maybe I'm not seeing clear anymore and hope you can help.
I'm trying to select an Object from a NSMutableArray using:
if([car.seat isEqualToString:#"fancyOne"]){
fancyThings = [[NSMUtableArray]init];
[fancyThings addObjects: car];
}
Now I forgot to tell you I'm new at this Objective-C, so maybe I'm thinking the wrong way.
What I'm basically trying to do is to get an Object from one array by selecting a value of it's components.
This is the way to do it, I am however keep having trouble with my if-statement.
If I leave out the IF-statement it does fill my other NSMutableArray with the exact same object (thisCar) but if I put in the IF-statement it doesn't pick up that the string is the same in thisCar.seat.
I next example it puts everything in the normalThings but there are some aCar.seats which contain the string FANCYONE. I checked the XML file on spaces and that sort of things but everything is in order as far as I can see.
Shall I build it using NSScanner instead of IsEqualToString?
- (void)viewDidLoad {
appDelegate = (XMLAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.fancyThings = [[NSMutableArray alloc]init];
for (CARS *aCar in appDelegate.someCars) {
if ([aCar.seats isEqualToString:#"FANCYONE"]){
[appDelegate.fancyThings addObject:aCar];
}
else {
[appDelegate.normalThings addObject:aCar];
}
}
self.title = #"Cars";
super viewDidLoad];
}
EDIT:
My BAD!! The code supplied was in fact in order!
There was a mistake in my XMLParser, which added blank lines to the strings, so I couldn't get an equal string!
Hopefully this will give you some guidance:
//init new array
NSMutableArray *fancyThings = [[NSMutableArray alloc] init];
//walk your array
for (SomeCarObject *thisCar in arrayOfCars) {
//is thisCar a qualifying object
if ([thisCar.seat isEqualToString:#"fancyOne"]) {
//yes, add thisCar object
[fancyThings addObject:thisCar];
}
}
You'll want to create that NSMutableArray outside of the for loop (assuming you're iterating through a collection). Then you can add to that NSMutableArray like you did.
Hope this helps!
BTW, you should edit your question with the comment you made to elaborate on it..
It's depends from volume of objects, which u deal with. If there is 1000 objects or less, this method looks good. But if there is more objects, u have risk to freeze u application and have a big memory leaks.
Also if u will need concurrency code later, u have to keep in u mind some
other solutions.
U can using not just a string objects in u array, u can try to fill u array after application startup in objects, which response if string is same or not. Or using nsdictionary with appropriate keys.
Please read my post multithread search design
Hey guys, lately I have been asking quite a few questions about memory management on the iPhone. Fortunately things are getting clearer. But I still struggle when it gets more complex: So is there something wrong with this in terms of memory mangement? My question and suggestions are in the comments...
//I get a text from a textfield
NSString *text = [[NSString alloc]initWithString:txtField.text];
NSMutableString *newText = [self replaceDynamicRegex:text];
[text release];
...
//The method replaces regex it finds in the text. The regex part is just pseudo code
//and I just interested in memory management
-(NSMutableString*)replaceDynamicRegex:(NSString*)txt{
NSString *currentTag = [NSString stringWithString:#"dynamiclyCreatedTag"];
//As long as we find a particuar regex (just pseuo code here) we replace it
while (currentTag != NULL) {
if([html stringByMatching:openingTag] == NULL){
break;
}
//regular expression
currentTag = [NSString stringWithString:[html stringByMatching:theRegex]];
//Get rid of the useless part of the currentTag pseudo code
NSString *uselessTagPart = #"uselessRegex";
//Reassignment of the pointer currentTag --> ok to do this? cause I did not alloc]init]?
//and instead used stringWithString wich then gets autoreleased
currentTag = [currentTag stringByReplacingOccurrencesOfRegex:uselessTagPart withString:#""];
//Reassignment of the pointer html --> Ok to do this? cause it is just a pointer and the
//object is being released after the method call (further up)
html = (NSMutableString*)[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag];
}
//Do I need to autorelease this?
return html;
}
Your code looks correct memory-management-wise. Just remember, if you don't have call a method with alloc, new, retain, or copy in the method name, you don't have to worry about releasing.
One small point--your first 3 lines of code are redundant and inefficient. You shouldn't usually use initWithString--copy is usually a better choice when dealing with immutable objects, since behind the scenes a copy method can be replaced by a (less expensive) retain method. In your case, you don't even need to use copy--[self replaceDynamicRegex: txtField.text] will have the same result. Likewise, instead of [NSString stringWithString:[html stringByMatching:theRegex]], you can use simply use [html stringByMatching:theRegex] (since that method returns a new string).
Another note--html = (NSMutableString*)[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag] is incorrect. stringByReplacingOccurrencesOfRegex: returns an NSString, which can't be cast to an NSMutableString (you'll likely get a crash later on when you send a mutating method to the string). Instead, use [[html stringByReplacingOccurrencesOfRegex:currentTag withString:replacementTag] mutableCopy]
Generally, when you see a method named xWithY, you can assume the string will be autorelease-d.
Therefore, you probably do not need to autorelease the value returned from -stringByReplacingOccurrencesOfRegex:withString:.
The rest of your code looks okay, to me.
I am building my first iPhone/Obj-c app and I have a large amount of data-holding subclasses that I am passing into a cite function. To the cite function these objects are anonymous and I need to find a way to access all the variables of each passed object.
I have been using a pre-built NSArray and Selectors to do this but with more than 30 entries (and growing) it is kind of silly to do manually. There has to be a way to dynamically look up all the variables of an anonymous object.
The obj-c runtime run-time docs mention this problem but from what I can tell this is not available in iPhone OS. If it is then I don't understand the implementation and need some guidance. A similar question was asked before but again I think they were talking about OSX and not iPhone.
Any thoughts?
-(NSString*)cite:(id)source {
NSString *sourceClass = NSStringFromClass([source class]);
// Runs through all the variables in the manually built methodList
for(id method in methodList) {
SEL x = NSSelectorFromString(method);
// further implementation
// Should be something like
NSArray *methodList = [[NSArray alloc] initWithObjects:[source getVariableList]]
for(id method in methodList) {
SEL x = NSSelectorFromString(method);
// Further implementation
}
The runtime is the same on the Mac as it is on the iPhone. If the other question does what you're looking for, then it should work. If it doesn't, file a bug.
In the meantime, given a Class, you can retrieve a list of all of its selectors using the class_copyMethodList() function:
unsigned int numMethods = 0;
Method * methods = class_copyMethodList(sourceClass, &numMethods);
NSMutableArray * selectors = [NSMutableArray array];
for (int i = 0; i < numMethods; ++i) {
SEL selector = method_getName(methods[i]);
[selectors addObject:NSStringFromSelector(selector)];
}
free(methods);
It's certainly possible to do this through the Objective-C runtime functions, but it's probably not the right way to go about it. Since you're creating the objects passed into the cite method, just have them each implement a protocol that cite can use to extract whatever information it needs.
Something like the Key-Value Coding protocol will probably do what you want:
http://developer.apple.com/iphone/library/documentation/cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html