UILabel Address label is blank and Local Declaration hides instance variable - objective-c

I am new to Xcode, and I am attempting to have my app access the Address Book, choose a person, and then create NSString values for the person (First Name, Last Name, Organization, Address, Email and Telephone Number) I can pull the first and last name, the organization, the first email entered (it would be nice to display all of the email address, and let the user choose), and the first phone number entered in (again, it would be nice to be able to choose), but the address for the person is always blank. I would really appreciate any help you can provide. In addition, I keep getting local declaration hides instance variable warnings - I have no idea how to resolve these.
#import "TACustomer.h"
#interface TACustomer ()
#end
#implementation TACustomer
#synthesize custfirstName;
#synthesize custlastName;
#synthesize custOrganization;
#synthesize custEmail;
#synthesize custAddress;
#synthesize custphoneNumber;
- (IBAction)showPicker:(id)sender
{
// Creating the Address Book Picker
ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
// Place the delegate of the picker to the control.
picker.peoplePickerDelegate = self;
// Showing the picker.
[self presentModalViewController:picker animated:YES];
}
- (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker
{
//assigning control back to the main controller.
[self dismissModalViewControllerAnimated:YES];
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
{
[self displayPerson:person];
[self dismissModalViewControllerAnimated:YES];
return NO;
}
- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property
identifier:(ABMultiValueIdentifier)identifier
{
// Only inspect the value if it's an address.
if (property == kABPersonAddressProperty)
{
//Set up an ABMultiValue to hold the address values; copy from a book record.
ABMutableMultiValueRef multicustValue = ABRecordCopyValue(person, property);
// Set up an NSArray and copy values into it.
NSArray *thecustArray = (__bridge id)ABMultiValueCopyArrayOfAllValues(multicustValue);
// Figure out which values we want and store the index.
const NSUInteger customerIndex = ABMultiValueGetIndexForIdentifier (multicustValue, identifier);
// Set up an NSDictionary to hold the contents of the array.
NSDictionary *custDict = [thecustArray objectAtIndex:customerIndex];
// Set up NSStrings to hold the keys and values. First, how many are there?
const NSUInteger theCount = [custDict count];
NSString * __unsafe_unretained keys[theCount];
NSString *__unsafe_unretained values[theCount];
// Get the keys and values from the CFDictionary.
[custDict getObjects:values andKeys:keys];
// Set the address label's text.
NSString *customeraddress;
customeraddress = [NSString stringWithFormat:#"%#, %#, %#, %#, %#",
[custDict objectForKey:(NSString *)kABPersonAddressStreetKey],
[custDict objectForKey:(NSString *)kABPersonAddressCityKey],
[custDict objectForKey:(NSString *)kABPersonAddressStateKey],
[custDict objectForKey:(NSString *)kABPersonAddressZIPKey],
[custDict objectForKey:(NSString *)kABPersonAddressCountryKey]];
self.custAddress.text = customeraddress;
}
return NO;
}
- (void)displayPerson:(ABRecordRef)person
{
// Get Customer First Name
NSString* custfirstname = (__bridge_transfer NSString*)ABRecordCopyValue(person,kABPersonFirstNameProperty);
self.custfirstName.text = custfirstname;
// Get Customer Last Name
NSString* custlastname = (__bridge_transfer NSString*)ABRecordCopyValue(person,kABPersonLastNameProperty);
self.custlastName.text = custlastname;
// Get Customer Organization
NSString* custorganization = (__bridge_transfer NSString*)ABRecordCopyValue(person,kABPersonOrganizationProperty);
self.custOrganization.text = custorganization;
//Get Customer Email Address
NSString* custemail = nil;
ABMultiValueRef custemailAddresses = ABRecordCopyValue (person,kABPersonEmailProperty);
if (ABMultiValueGetCount(custemailAddresses) > 0)
{
custemail = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(custemailAddresses, 0);
} else
{
custemail = #"[None]";
}
self.custEmail.text = custemail;
CFRelease(custemailAddresses);
// Get Customer Phone Number
NSString* custphone = nil;
ABMultiValueRef phoneNumbers = ABRecordCopyValue (person,kABPersonPhoneProperty);
if (ABMultiValueGetCount(phoneNumbers) > 0)
{
custphone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
} else
{
custphone = #"[None]";
}
self.custphoneNumber.text = custphone;
CFRelease(phoneNumbers);
bundle:nil;
//[self.navigationController pushViewController:tempExamInfoView animated:YES];
}
#end

I have no answer for the problem that the address data is blank.
To get rid of the "local declaration hides instance variable" warning you need to use different variable names that do not clash with the names of the properties you are synthesizing.
For instance, in displayPerson: you have a local variable custfirstname. Because this uses the same name as a property, the local variable hides the instance variable of the same name that is being synthesized.
If you want to keep the local variable name, I believe it is also possible to tell #synthesize to use a different name for the instance variable that it generates. I am not familiar with the syntax, so if you want to go that way you have to look it up yourself.

Related

How to parse and take only this string value

I wanted to get only array string value app. As example(SLGoogleAuth ,HalfTunes,TheBackgrounder,Calculiator) . But don't know how to do?
It's a code.
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector=NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSLog(#"apps: %#", [workspace performSelector:selectorALL]);
}
It's output:
Thanks in advance
You do not want to parse that. NSLog prints out a description of an object. You want to access that value directly.
[LSApplicationWorkspace allApplications];
returns NSArray of LSApplicationProxy. LSApplicationProxy class has a ivar _bundleURL that contains information that you need. You need runtime functions to access it. Working example below:
// #import <objc/runtime.h>
Class LSApplicationWorkspace_class = objc_getClass("LSApplicationWorkspace");
SEL selector=NSSelectorFromString(#"defaultWorkspace");
NSObject* workspace = [LSApplicationWorkspace_class performSelector:selector];
SEL selectorALL = NSSelectorFromString(#"allApplications");
NSArray* appProxies = [workspace performSelector:selectorALL];
Ivar bundleUrlIvar = class_getInstanceVariable([appProxies.firstObject class], "_bundleURL");
NSMutableString* result = [NSMutableString string];
for (id appProxy in appProxies)
{
NSURL* url = object_getIvar(appProxy, bundleUrlIvar);
// at this point you have the information and you can do whatever you want with it
// I will make it a list as you asked
if (url)
{
[result appendFormat:#",%#", [url lastPathComponent]];
}
}
if (result.length > 0)
{
// remove comma from beginning of the list
[result deleteCharactersInRange:NSMakeRange(0, 1)];
}
NSLog(#"apps: %#", result);
Note that this will be rejected by AppStore as you are using private apis. So use at your own discretion.

string not populating with array data, even though arrays are not really empty

I am trying to create a non-Document-based application for Mac OS X that randomizes cards for the game of Dominion.
From many of the ones I have tried, the only thing I cannot seem to do is limit the number of sets picked from a selection made by the user, and things worked pretty well in my program, but I am having issues.
I am trying to get the results to print in a custom view, but every time I look at the print preview, nothing shows, except header text, as specified in an NSMutableString.
This piece of code is what is being used to print and is found in MasterViewController:
- (IBAction)print:(id)sender
{
NSMutableString *content = [[NSMutableString alloc] initWithString:#"Cards\r\n\r\n"];
for (int i = 0; i < [supply.game count]; i++)
{
[content appendFormat:#"Card: %# Set: %# Cost: %d\r\n", [supply.game[i] name], [supply.game[i] collection], [supply.game[i] cost]];
}
[content appendFormat:#"\r\n\r\nRequired\r\n\r\n"];
for (int i = 0; i < [[setup supply] count]; i++)
{
NSDictionary* current = [setup supply][i];
NSString* key = [current allKeys][0]; // get the key of the current dictionary must be 0, as there is only one key
int value = [[current valueForKey:key] integerValue]; // variable to hold key value
if (value > 0) {
[content appendFormat:#"%#: %#", key, #"Yes"];
}
else
{
[content appendFormat:#"%#: %#", key, #"No"];
}
}
printView.content = [NSMutableString stringWithString:content];
[printView print:sender];
}
the data initially gets filled into some tableviews, which displays the correct content, and the supply.game array is the exact array that contains cards used for games.
setup is a property that refers to a view controller that populates a table with kinds of cards that may be required for games (e.g. shelters, colonies, ruins, spoils, and potions) and the supply method is supposed to return the array that view controller creates, which is itself not empty, as that table populates properly.
printView is a property that is assigned to a custom view found in MainMenu.xib and is the real view being used to print from.
the printView class looks like this:
header:
#import <Cocoa/Cocoa.h>
#interface PrintView : NSView
{
NSMutableString* content;
}
#property NSMutableString* content;
- (void)drawStringInRect:(NSRect)rect; // method to draw string to page
- (void)print:(id)sender; // method to print
#end
implementation:
#import "PrintView.h"
#implementation PrintView
#synthesize content;
- (BOOL)acceptsFirstResponder
{
return YES;
}
- (void)print:(id)sender
{
[[NSPrintOperation printOperationWithView:self] runOperation];
}
- (void)drawRect:(NSRect)dirtyRect {
NSGraphicsContext *context = [NSGraphicsContext currentContext];
if ([context isDrawingToScreen])
{
}
else
{
[[NSColor whiteColor] set];
NSRect bounds = [self bounds];
if (content == nil || [content length] == 0)
{
NSRectFill(bounds);
}
else
{
[self drawStringInRect:bounds];
}
}
}
- (void)drawStringInRect:(NSRect)rect
{
NSSize strSize; // variable to hold string size
NSPoint strOrigin; // variable used to position text
NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
[attributes setObject:[NSFont fontWithName:#"Helvetica" size:12] forKey:NSFontAttributeName];
[attributes setObject:[NSColor blackColor] forKey:NSForegroundColorAttributeName];
strSize = [content sizeWithAttributes:attributes];
strOrigin.x = rect.origin.x + (rect.size.width - strSize.width)/2;
strOrigin.y = rect.origin.y + (rect.size.height - strSize.height)/2;
[content drawAtPoint:strOrigin withAttributes:attributes];
}
#end
When I check the array sizes for printing operation, the size of the arrays is reported as zero, thus resulting in my current problem
If you need more code, here is code from Github, but I do not have the experimental branch up there, which is where the above code came from, though it should not be too different.
The MasterViewController will show how the supply.game array is made and SetupViewController houses the code that is used to determine what is needed in the game, as well as show how the supply array from [setup supply] is being produced.
MasterViewController has also been added as an object to MainMenu.xib, so I do not know if that affects anything.
Any idea of what I need to do?
Edit: Added in info that might be relevant

NSMutableDictionary - entries appear to be over-written by each addition

I'm fairly new to Objective-C; but have been coding for years and this one really stumps me.
I'm trying to build an iPhone app and wanted to create a "settings" screen which will use a Table format. (Xcode 5.1.1).
I want to future proof the main Settings screen and make it easy for the application coding by hiding the "hard work" in subroutines/methods.
I may be getting too clever but I've created a class for each 'setting' that contains screen prompts, default values etc and using an Enum to cross-reference it (so the compiler will highlight typos etc)
The problem I'm encountering is that when I add entries to my NSMutableDictionary and use lldb to print the values; every entry seems to have the same "key" and values. I've tried converting the eNum to an NSNumber and also as an NSString -- no difference in the result - so I'm obviously doing something else daft but just can't see it
The following code is from various .m & .h files, I've omitted boring stuff that you always "have to have" to keep it short
// basic x-ref I want to use in my code
typedef NS_OPTIONS(NSInteger, ConfigurationType) {
unDefined = -1,
Server = 0,
Id = 1,
Phone = 2
};
// definition for a "single" Settings value
#interface SettingDefinition : NSObject
#end
#implementation SettingDefinition
ConfigurationType _cfgType;
NSString *_cfgName;
NSString *_screenTitle;
NSString *_value;
- (NSString *)description
{
NSString *className = NSStringFromClass([self class]);
return [NSString stringWithFormat:#"<%#: x%p Type=%d dbKey=%# '%#' -> %#>", className, self, _cfgType, _cfgName, _screenTitle, _value];
}
- (id)initType:(ConfigurationType)cfgOption
withDbKey: (NSString*)dbKey
asOptionTitle:(NSString*)cfgTitle
withValue:(NSString*)itmValue
{
self = [super init];
if (self) {
_screenTitle = cfgTitle;
_cfgName = dbKey;
_cfgType = cfgOption;
_value = itmValue;
}
return self;
}
#end
#interface Configuration : NSObject
#end
#implementation Configuration {
NSMutableDictionary *Settings; // List of Setting structures
};
- (id)init {
self = [super init];
if (self) {
Settings = [[NSMutableDictionary alloc]init];
[self add:Server withDbKey:#"Server" asOptionTitle:#"Server"];
[self add:Id withDbKey:#"Id" asOptionTitle:#"Your ID"];
[self add:Phone withDbKey:#"Phone" asOptionTitle:#"Phone No."];
}
return self;
}
- (void) add:(ConfigurationType)cfgOption
withDbKey:(NSString*)dbKey
asOptionTitle:(NSString*)cfgTitle
{
NSString * itmValue = [self configurationValue: cfgOption cfgName:dbKey];
SettingDefinition *x = [[SettingDefinition alloc]
initType: cfgOption
withDbKey: dbKey
asOptionTitle: cfgTitle
withValue: itmValue];
[Settings setObject:x forKey:[self asKey:cfgOption]];
}
- (NSString *) asKey:(ConfigurationType) settingType {
NSString *rc = [NSString stringWithFormat:#"%d", settingType];
return rc;
}
- (NSString *) configurationValue:(ConfigurationType) settingType {
// returns a suitable value from my system setup
// which is initially a null value until the user sets everything up
}
the debug window shows the following when I break after the final call to [self add: ...]
(lldb) po Settings
{
0 = "<SettingDefinition: x0x8e7c280 Type=2 dbKey=Phone 'Phone No.' -> (null)>";
1 = "<SettingDefinition: x0x8c703a0 Type=2 dbKey=Phone 'Phone No.' -> (null)>";
2 = "<SettingDefinition: x0x8e7c310 Type=2 dbKey=Phone 'Phone No.' -> (null)>";
}
The (null) is obviously due to no data in 'value' yet; but why do they all show as 'Phone'; if I break after the second call to [self add:..] they all show as 'Id'
UPDATE:
DOH! obviously they're globals (I've been using another IDE where everything is local until exposed) .. If I enclose them in braces in the implementation as the documentation states then the exhibited problem vanishes. I have properties to access the variables but as the setter does more than just set the memory, I thought I'd need my "own" variables to hold the data.. said it was something daft .. thank you!

Objective C: Memory Management, releasing an object with multiple references

I would like to release a Car object present in the dealer. I would like to know what is the right way of doing it. NSMutableArray Inventory stores the cars for a particular dealer. So, now I would like to present the user with a delete functionality, so, user could select the car using the Vin Number and delete it. But if I try to find the car and release the reference that doesn't works. Would I need to remove the object from the Array and then, release the reference? I am fairly new to objective c and in the initial learning phase. Thank you.
#import "Dealer.h"
#import "Address.h"
#import "PhoneNumber.h"
#implementation Dealer
static NSInteger dealerIdAllocater = 0;
-(id) init{
self = [super init];
self.dealerId = ++dealerIdAllocater;
self.addressList = [[NSMutableArray alloc] init];
self.inventory = [[NSMutableArray alloc] init];
return self;
}
#synthesize dealerId, name, addressList, inventory;
-(void)addCarInInventory:(Car*)car{
[self.inventory addObject: car];
}
-(void)displayAddresses{
for(Address *address in self.addressList){
NSLog(#"Street Address: %#", address.streetAddress);
NSLog(#"City: %#", address.city);
NSLog(#"State: %#", address.state);
NSLog(#"Country: %#", address.country);
for(int i=0; i<[address.phoneNumber count]; i++){
PhoneNumber *phoneNumber = [address.phoneNumber objectAtIndex:i];
NSLog(#"Phone Number %i, %#", i, phoneNumber.phoneNumber);
}
NSLog(#"--------------");
}
}
-(void)displayInventory{
for(Car *car in self.inventory){
[car displayInformation];
}
NSLog(#"--------------");
}
-(Car *)findCarById:(NSString *)vinNumber{
for(Car *car in self.inventory){
if ([vinNumber isEqualToString:car.vinNumber]) {
return car;
}
}
return nil;
}
#end
Would I need to remove the object from the Array and then, release the reference?
Yes, containers such as NSMutableArrays increment the retain count of objects by 1 when added to them. This is to make sure the container will always hold a valid reference to an object. When you remove an object from the container, the retain count will be decremented by 1.

How can I get an NSString value from a "(void)" method into a "(BOOL)" method in Objective-C?

I want to get the value of "city" into "CurrentLocation".
- (void)reverseGeocoder:(MKPlacemark *)placemark {
NSString *city = [myPlacemark.addressDictionary objectForKey:(NSString*) kABPersonAddressCityKey];
}
- (BOOL)fetchAndParseRSS {
NSString *currentLocation; // I want 'city' here.
return YES;
}
Why are your returning void from your reverseGeocoder message? I would have written this like this:
- (NSString*)reverseGeocoder:(Placemark*)myPlacemark
{
// assuming myPlacemark is holding a reference to the dictionary (so no need to retain)
NSString *city = [myPlacemark.addressDictionary objectForKey:kABPersonAddressCityKey];
return city;
}
-(BOOL)fetchAndParseRss
{
// you need to get myPlacemark from somewhere, presumably from the geocode request?
Placemark * myPlacemark = [self getPlacemark];
NSString * CurrentLocation = [self reverseGeocoder:myPlacemark];
}
In this code I am assuming Placemark is a class with a addressDictionary NSDictionary defined as a property.
If you really need that message to return a void* then you would cast from a NSString* to void* and then back again.
- (void*)reverseGeocoder:(Placemark*)myPlacemark
{
// assuming myPlacemark is holding a reference to the dictionary (so no need to retain)
NSString *city = [myPlacemark.addressDictionary objectForKey:kABPersonAddressCityKey];
return (void*)city;
}
Then cast it back to an NSString when you assign it (not sure why you would do this):
-(BOOL)fetchAndParseRss
{
// you need to get myPlacemark from somewhere, presumably from the geocode request?
Placemark * myPlacemark = [self getPlacemark];
NSString * CurrentLocation = (NSString*)[self reverseGeocoder:myPlacemark];
}