Use NSString variable created in viewDidLoad inside another method - objective-c

In my viewDidLoad method, I set the following variables:
// Get requested URL and set to variable currentURL
NSString *currentURL = self.URL.absoluteString;
//NSString *currentURL = mainWebView.request.URL.absoluteString;
NSLog(#"Current url:%#", currentURL);
//Get PDF file name
NSArray *urlArray = [currentURL componentsSeparatedByString:#"/"];
NSString *fullDocumentName = [urlArray lastObject];
NSLog(#"Full doc name:%#", fullDocumentName);
//Get PDF file name without ".pdf"
NSArray *docName = [fullDocumentName componentsSeparatedByString:#"."];
NSString *pdfName = [docName objectAtIndex:0];
I would like to be able to use these variables inside of another method (i.e. - (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {)
How can I reuse these variables outside of the viewDidLoad method? I'm a newbie... help would be SO much appreciated

Make them an instance variable and not a variable local to the method you're using. After that, you can access them from all methods of the same class.
Example:
#interface MyClass: NSObject {
NSString *currentURL;
// etc.
}
- (void)viewDidLoad
{
currentURL = self.URL.absoluteString;
// etc. same from other methods
}

In terms of "global-variables" (as you tag says) within your class where you define the viewDidLoad create them as instance variables.
In your .h of the class
#interface MyViewController : UIViewController
{
NSArray *docName;
NSString *pdfName;
...
}

In your #interface (in the .h file) include this:
#property (nonatomic, strong) NSString *currentURL;
// the same for the rest of your variables.
Now you'll be able to access these properties by calling self.currentURL. If this is a newer project and ARC is turned on you don't have to bother with managing memory yourself.

Make them instance variable as H2CO3 suggests. Also you could just derive all your variables in the actionSheet:clickedButtonAtIndex function itself.
I notice that all the required variables are derived from self.URL.absoluteString. Therefore there should be no problem moving all your code, because self.URL is your instance variable that is holding what you want.
- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// Get requested URL and set to variable currentURL
NSString *currentURL = self.URL.absoluteString;
//NSString *currentURL = mainWebView.request.URL.absoluteString;
NSLog(#"Current url:%#", currentURL);
//Get PDF file name
NSArray *urlArray = [currentURL componentsSeparatedByString:#"/"];
NSString *fullDocumentName = [urlArray lastObject];
NSLog(#"Full doc name:%#", fullDocumentName);
//Get PDF file name without ".pdf"
NSArray *docName = [fullDocumentName componentsSeparatedByString:#"."];
NSString *pdfName = [docName objectAtIndex:0];
// Do what you need now...
}

Related

Why is my NSMutableArray, located in a singleton, returning (null)?

I am working in Xcode 4.5.1 in Objective-C. I’m making a hearing test and want to store relevant data to each question in an array. I made a singleton MyManager. I use this to store data.
It is working fine for simple int/float values etc., but I’m stuck trying to use NSMutableArray. I’m new to Objective-C, so I’m assuming/hoping I've made some obvious mistake.
So, I want to fill mySNRArray with float values. I’ve come to understand that I can’t simply add floats, because it will only take objects. Thus, I use NSNumber.
Problem: When I try to read the data that I’ve supposedly added to the NSMutableArray, I get (null).
I will now provide the relevant code:
MyManager.h
#interface MyManager : NSObject
{
NSMutableArray *mySNRArray;
}
#property (readwrite) NSMutableArray *mySNRArray;
+ (id)sharedManager;
#end
MyManager.m
#implementation MyManager
#synthesize mySNRArray;
+ (id)sharedManager
{
static MyManager *sharedMyManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^
{
sharedMyManager = [[self alloc] init];
});
return sharedMyManager;
}
- (id)init
{
if (self = [super init])
{
NSMutableArray *mySNRArray = [[NSMutableArray alloc]init];
}
return self;
}
#end
TestViewController.m
//First, I try to add a value to mySNRArray.
MyManager *Manager = [MyManager sharedManager];
NSNumber *tempStorage1 = [[NSNumber alloc] initWithFloat:mySNR];
[Manager.mySNRArray insertObject:tempStorage1 atIndex:questionNumber];
//The NSLog below is showing the correct value.
NSLog(#"%# : mySNR", tempStorage1);
...
for (n = 0; n < questionNumber; n++)
{
//Second, I try to acces the values I supposedly added to mySNRArray.
MyManager *Manager = [MyManager sharedManager];
//This NSLog below is showing (null).
NSLog(#"Value at %i in SNRArray = %#", n, [Manager.mySNRArray objectAtIndex:n]);
}
...
I hope somebody can explain my error.
change
NSMutableArray *mySNRArray = [[NSMutableArray alloc]init];
to
self->_mySNRArray = [[NSMutableArray alloc]init];
in your init method you are creating a local mutable array, but not assigning it to your property
Instead of creating a new object, use the ivar you created..in the init method.
_mySNRArray = [[NSMutableArray alloc]init];
Even you can ommit these, from your .h
{
NSMutableArray *mySNRArray;
}
+ (id)sharedManager
returns a value
static MyManager* sharedManager
Change the interface to
+ (MyManager*)sharedManager
and the compiler will tell you exactly what mistake you made.

Accessing NSDictionary in Singleton Class w/o Creating Copies

I have a singleton as follows, which creates an instance of NSDictionary to hold my data. Here is the .h:
#interface FirstLast : NSObject
#property (strong, nonatomic, readonly) NSArray *firstArray;
#property (strong, nonatomic, readonly) NSArray *lastArray;
#property (strong, nonatomic, readonly) NSDictionary *fl;
+ (FirstLast *) firstLast;
- (NSDictionary *) tempDic;
#end
Here is the .m
#implementation FirstLast
#synthesize firstArray = _firstArray;
#synthesize lastArray = _lastArray;
#synthesize fl = _fl;
+ (FirstLast *)firstLast {
static FirstLast *singleton;
static dispatch_once_t once;
dispatch_once(&once, ^{
singleton = [[FirstLast alloc] init];
NSLog(#"FirstLast instantiated");
});
return singleton;
}
- (NSDictionary *) tempDic{
_firstArray = [[NSArray alloc] initWithObjects:#"Bob", #"Joe", #"Sally", #"Sue", nil];
_lastArray = [[NSArray alloc] initWithObjects:#"Jones", #"Johnson", #"Thompson", #"Miller", nil];
_fl = [NSDictionary dictionaryWithObjects:_firstArray
forKeys:_lastArray];
NSLog(#"tempDic just made _fl at this address");
NSLog(#"%p", _fl);
return _fl;
}
#end
All of this works fine. In the view controller I instantiate all this for the first time (works fine too):
NSLog(#"VC is setting up tempDic");
[[WordsClues wordsClues] tempDic];
When I try to gain access to tempDic elsewhere, like this:
NSInteger rIndex = arc4random_uniform(4) + 1;
NSString *fname = [[[FirstLast firstLast].tempDic allValues] objectAtIndex:rIndex];
it works fine, but, when I repeat this process, each time I'm creating a new tempDic. I know this because the NSLog giving the address gives a different answer each time. I really want to access the existing dictionary, which is what I thought my singleton was going to accomplish. Clearly I'm either not accessing tempDic correctly or I misunderstand what the singleton can do for me or I have the tempDic set up wrong. The goal is to get a random value from a single copy of tempDic and not write local copies of tempDic all over the place. Thanks.
Why do you recreate the dictionary in -tempDic at all?
I.e. move the dictionary instantiation code to init and then just return _fl; in tempDic.
No worries -- we've all been there [new].
In your FirstLast class, implement the init method as something like:
- init
{
self = [super init];
if ( self ) {
_fl = ... create your dictionary here ...;
}
return self;
}
Then change -tempDic to:
- (NSDictionary*)tempDic {
return _fl;
}
I would highly recommend that you read a good intro to Objective-C book. I'm a purist and, thus, would recommend going to the source for the information, but there are lots of books available.
The questions you are asking are more in line with "What is object oriented programming and how does Objective-C work?".
To answer your question; FirstLast is a class and the singleton pattern makes sure there is exactly one instance of that class. By moving the creation of the dictionary to the init method -- which is called only once and who stores a reference to the created dictionary in an instance variable -- you avoid creating multiple dictionary instances.
Every time you call tempDic, you create a new copy of it. What you should do is add you code for creating the dictionary to your alloc instance, and then just retrieve it in your getter.
Alternativly you can do this
- (NSDictionary *) tempDic{
if( _fl == nil )
{
_firstArray = [[NSArray alloc] initWithObjects:#"Bob", #"Joe", #"Sally", #"Sue", nil];
_lastArray = [[NSArray alloc] initWithObjects:#"Jones", #"Johnson", #"Thompson", #"Miller", nil];
_fl = [NSDictionary dictionaryWithObjects:_firstArray
forKeys:_lastArray];
NSLog(#"tempDic just made _fl at this address");
NSLog(#"%p", _fl);
}
return _fl;
}

What is an import statement where filename contains "+"?

I have seen in some source code (by other developers) something like this:
#import "SomeClass+SomeOtherClass.h"
What is the + for? What does this mean?
Let's say you want to add functionality to an existing class (exp: NSString). You can do that by creating a subclass or you can use a category. And it is common to name the file where the category is defined using the pattern : MyClass+MyCategory.h.
For example, we can add a method reverseString to the class NSString in a category:
// File NSString+reversable.h
- (NSString *)reverseString;
// File NSString+reversable.m
- (NSString *)reverseString
{
// Implementation
}
Have a look at this documentation for more information about categories.
Then you can use that category in another class:
#import "NSString+reversable.h"
// ...
NSString *aString = #"Hello!";
NSString *reversedString = [aString reverseString];
The "+" in header/source filenames is - by convention - used to describe Category implementations.
Example :
Let's say you want to add some functionality to an existing class (e.g.the NSString class). (NSString+Utilities.h)
// NSString+Utilities.h
#interface NSString (Utilities)
-(NSString *) doSthWithThisString;
#end
// NSString+Utilities.m
#implementation NSString (Utilities)
-(NSString *) doSthWithThisString
{
NSMutableString *transformedStr = [self copy];
// Do sth
return transformedStr;
}
#end
Using it :
// in another file
#import "NSString+Utilities.h"
- (void)awakeFromNib
{
NSString* myString = #"This is a string";
// you may use our new NSString method as much as any already-existing one
NSString* newString = [myString doSthWithThisString];
}
Reference :
Mac OS Developer Library - Categories & Extensions
Objective-C Categories - Wiki

iOS - NSMutableArray shows objects out of bounds on setting property

I have implemented the following code to assign NSMutableArray to a property -
NSMutableArray * anArray = [responseDictionary valueForKeyPath:#"tags"];
NSLog(#"The array length is=%d",[anArray count]);
for (NSString *s in anArray) {
NSLog(#"you are %#", s);
}
[self setActiveTagArray:anArray];
It prints out the string values fine. But in the setter function, if I place a breakpoint I see that it shows there are two objects but they are "Out of Scope". What does this mean? What am I doing wrong? My getter also does not fetch any values. The property functions -
-(void)setActiveTagArray:(NSMutableArray *)tags
{
activeTagArray = [[NSMutableArray alloc] init];
activeTagArray = tags;
//NSLog(#"%#",[activeTagArray count]);
}
-(NSMutableArray *)getActiveTagArray
{
return activeTagArray;
}
Is activeTagArray a class variable as well as a property. Consider using _activeTagArray as the class variable name. And then in the .m file just use #synthesize activeTagArray = _activeTagArray;, and for get the second two methods completely.
Response to comment:
You said "I have implemented the following code to assign NSMutableArray to a property". I took this to mean you have "#property (nonatomic, retain) NSMutableArray *activeTagArray;" in your .h file. If this is the case then you would access it thru otherObject'sNameForYourClassHere.activeTagArray.
#synthesize create accessors & mutators for you.

Localizing Core Data model properties for display

I'm working on an iOS project that uses a large and fairly complex data model. Some of the entities in the model have corresponding detail view controllers, which include table views that should display localized names and the corresponding values of certain properties.
I've looked at some of Apple's documentation for creating a strings file for a managed object model, but most of it seems geared toward displaying error messages generated by the SDK rather than accessing localized property names directly.
I created a strings file ("ModelModel.strings") for my model file ("Model.xcdatamodel"), and verified that it is loading correctly by looking at -localizationDictionary on my NSManagedObjectModel instance. My question is: how should I access the localized entity and property names in my code? Is there a way to get to them via NSEntityDescription, NSPropertyDescription, etc. or do I have to go through the NSManagedObjectModel every time?
I'm new at localization, so maybe the answer is obvious, but if so, feel free to just give me a nudge in the right direction.
Update
Following #ughoavgfhw's answer, I quickly came up with two categories to accomplish what I needed. Gist: https://gist.github.com/910824
NSEntityDescription:
#interface NSEntityDescription (LocalizedName)
#property (nonatomic, readonly) NSString *localizedName;
#end
#implementation NSEntityDescription (LocalizedName)
#dynamic localizedName;
- (NSString *)localizedName {
static NSString *const localizedNameKeyFormat = #"Entity/%#";
NSString *localizedNameKey = [NSString stringWithFormat:localizedNameKeyFormat, [self name]];
NSString *localizedName = [[[self managedObjectModel] localizationDictionary] objectForKey:localizedNameKey];
if (localizedName) {
return localizedName;
}
return [self name];
}
#end
NSPropertyDescription:
#interface NSPropertyDescription (LocalizedName)
#property (nonatomic, readonly) NSString *localizedName;
#end
#implementation NSPropertyDescription (LocalizedName)
#dynamic localizedName;
- (NSString *)localizedName {
static NSArray *localizedNameKeyFormats = nil;
if (!localizedNameKeyFormats) {
localizedNameKeyFormats = [[NSArray alloc] initWithObjects:#"Property/%#/Entity/%#", #"Property/%#", nil];
}
for (NSString *localizedNameKeyFormat in localizedNameKeyFormats) {
NSString *localizedNameKey = [NSString stringWithFormat:localizedNameKeyFormat, [self name], [[self entity] name]];
NSString *localizedName = [[[[self entity] managedObjectModel] localizationDictionary] objectForKey:localizedNameKey];
if (localizedName) {
return localizedName;
}
}
return [self name];
}
#end
There is no direct way to get that information provided by apple, but you could implement it yourself. You just need to add categories to NSEntityDescription, etc. which create the identifier and ask for the localized value from the model, and then treat it as if it were built in.
Here is an example NSEntityDescription implementation. For properties, you would do something similar, but you should use both the entity and property name in case multiple entities have properties with the same name (you may also need to use both the entity and property name as keys in your localization file. I don't know if the model will create them automatically).
#implementation NSEntityDescription (Localization)
- (NSString *)localizedName {
NSString *key = [NSString stringWithFormat:#"Entity/%#", [self name]];
NSDictionary *dictionary = [[self managedObjectModel] localizationDictionary];
NSString *localizedName = [dictionary objectForKey:key];
return (localizedName ? localizedName : [self name]);
}
#end
Here is a reference for the keys used in the localizations.