Syntax to access objects in my NSMutableArray - ios

I have 2 objects in an NSMutableArray one is a CBPeripheral object and the other is an NSString.
Here you can see that the NSMutableArray contains the two objects:
Then, in line 1249, I try to assign the 'periph' object to a CBPeripheral and in line 1252 I try to assign the 'ADVTname' to a text label.
Neither line 1249 nor 1252 is the correct syntax for what I am trying to do (line 1252 won't even compile).
Can someone tell me how to access my objects in my 'thisrow' NSMutableArray?
Thanks,
Dale
EDIT #1: I am trying to understand how 'thisrow' has become an NSDictionay but I am stumped, here are all the code snippets that put the objects into 'thisrow'. Perhaps there is a flaw in the whole idea I have that is trying to remember the ADVTname for all peripherals that got added to _foundbleHalos.
//AFTER #interface foundblehalos was defined
#property (strong,nonatomic) NSMutableArray* foundbleHalos;
//in (void)centralManager > didDiscoverPeripheral
[_foundbleHalos addObject:#{#"periph": peripheral, #"ADVTname": ADVRTperipheralName}]; //2022-b70-3
//when I try to populate a TableView with all the ADVTnames we found:
NSMutableArray *thisrow = [_foundbleHalos objectAtIndex:indexPath.row];
blecell.textLabel.text = [NSString stringWithFormat:#"%#",thisrow.lastObject];
CBPeripheral* HaloForRow = (CBPeripheral*) thisrow[0];
EDIT #2: Well I think this following code is the answer to my topic question but I do not understand it since I do not know why 'thisrow' turned out to be a dictionary type when I originally defined it as an NSMutableArray:
//AFTER #interface foundblehalos was defined
#property (strong,nonatomic) NSMutableArray* foundbleHalos;
//in (void)centralManager > didDiscoverPeripheral
[_foundbleHalos addObject:#{#"periph": peripheral, #"ADVTname": ADVRTperipheralName}]; //2022-b70-3
//when I try to populate a TableView with all the ADVTnames we found:
NSDictionary *thisrow = [_foundbleHalos objectAtIndex:indexPath.row];
blecell.textLabel.text = thisrow[#"ADVTname"];
CBPeripheral* HaloForRow = (CBPeripheral*) thisrow[#"periph"];

Related

Self looks like an array

I'm building an app whereas I have a UITableViewController set up as static and grouped. I'm using StoryBoard.
I have a breakpoint in my code where self looks like an array as it says "0 Objects" while it's a UITableViewController. Does anyone have a clue on why this is? Same happens if I use the class name as a cast. Just need an explanation for this.
V[0] is supposed to be an NSMutableArray, I init it like this, oldArray contains 3 objects (valid and correct objects)
_newArray = [[NSMutableArray alloc] initWithArray:oldArray];
But it doesn't look correct, neither does it work properly or log any objects. It logs out as nil when doing po _newArray
Thanks!
Update: fix
I changed it to a property instead of declaring it in #interface like so:
#property (nonatomic, strong) NSMutableArray *newArray;
and populated it using a function like so:
self.newArray = [NSMutableArray arrayWithArray:[self myArray]];
whereas myArray is a function with NSArray as return type. Looks like that fixed it, any comments on that?

JSONModel: Filling an NSArray of generic type

I'm using JSONModel in my iOS app and i'm facing some warnings, let me explain myself a bit.
Let's say i have this JSONModel
CTVContact.h
#interface CTVContact : JSONModel
#property (nonatomic, strong) NSArray<Optional, CTVPhone> *phone;
#end
CTVContact.m
NSMutableArray *phones = [[NSMutableArray alloc] init];
for(NSString *p in personPhones) {
CTVPhone *phn = [[CTVPhone alloc] init];
phn.original = p;
[phones addObject:phn];
}
phone = [NSArray arrayWithArray:phones];
Basically it all works like a charm but i get a warning stating the following:
Incompatible pointer types assigning to 'NSArray<Optional,CTVEventParticipant> *' from 'NSArray *'
How can i go around that warning? I can't find the right way to assign all the array values to the phone Array without that warning.
Thanks a lot in advance!
NSArray<Optional, CTVPhone> *phone; defines a variable that takes an array which conforms to 2 protocols. If you try and set that a variable (phone) to an array that doesn't state that it conforms to those protocols then you will get a compile warning.
phone = [NSArray arrayWithArray:phones]; just creates a 'plain' array, with no special protocols implemented. So you get a warning.
Probably the correct thing to do is to remove the protocols from the #property definition. Unless you have an NSArray subclass which conforms to those protocols that you should actually be using...
Alternatively, and assuming that you don't try to call any methods that might be defined in those protocols:
phone = (NSArray <Optional, CTVPhone> *)[NSArray arrayWithArray:phones];
which adds a cast that basically means to the compiler: 'trust me, it's fine'...
It looks like it may be complaining on your last line, since you're passing in an NSMutableArray when NSArray's arrayWithArray method calls for an NSArray. You can get away with this by calling copy on the phones array, as such:
phone = [NSArray arrayWithArray:[phones copy]];

NSArray Thread 1 error on scrolling

I am using a NSArray to store the names of pictures that I want to use in a UITableViewCell. When I pull the table view too much to scroll the app crashes and gives me:
Thread 1: EXC_BAD_ACCESS (code=2, address=0xc).
This is what I'm using to initialize my Array:
In my .h:
#property (retain, nonatomic) NSArray *imagesToDisplay;
In my .m:
(viewDidLoad)
_imagesToDisplay = #[#[#"one.png", #"two.png", #"three.png"],
#[#"four.png", #"five.png", #"six.png"],
#[#"seven.png", #"eight.png", #"nine.png"],
#[#"ten.png", #"eleven.png", #"twelve.png"],
#[#"thirteen.png", #"fourteen.png", #"fifteen.png"],
#[#"sixthteen.png", #"seventeen.png", #"eighteen.png"]
];
This is what I'm doing to retrieve the image and set the image view as those images:
int row = [indexPath row];
cell.image1.image = [UIImage imageNamed:self.imagesToDisplay[row][0]];
cell.image2.image = [UIImage imageNamed:self.imagesToDisplay[row][1]];
cell.image3.image = [UIImage imageNamed:self.imagesToDisplay[row][2]];
Even when I comment out the different cell.image lines they still give me the thread 1 error. My specific error is
Thread 1: EXC_BAD_ACCESS (code=2, address=0xc).
I'm new to objective c so anything helps. Thank you in advance!
I'm not sure if this is merely an exercise in multi-dimensional arrays but I would recommend against this.
Your first step should be to create a proper data model (class object) for your table. For example:
#interface ImageRow : NSObject
#property (nonatomic, copy) NSArray *imagePaths;
- (id)initWithArray:(NSArray *)array;
- (NSString)imagePathAtIndex:(NSUInteger)index;
#end
Then you would store an NSArray of ImageRows instead of the multi-dimensional array. Fundamentally, you are accomplishing the same thing but it's both more clear and more extensible.
Your crash EXC_BAD_ACCESS is typically when you try to access an object that is nil when you're expecting it not to be. In most cases, Obj-C will handle it gracefully but there are times where it does not.
The crash is because you are not retaining an autoreleased object. When you say a property is retain, the memory management is only done for you if you use its setter, typically by using self.property =. You are instead accessing the backing ivar directly. Because array literals are autoreleased and you have failed to retain it, the array is autoreleased and _imagesToDisplay points to garbage. Add a retain call or use its setter to fix this.
Also SiLo is right about the data model.

How to access specific column in NSArray using Xcode

I'm new to iOS programming. I'm trying to bind the specific field from the objects in an array to a UITableView. Here's my code:
NSArray *personInfo; //contains a record with fields: name, address, email
personInfo = [[PersonDatabase database] getAllPersons]; //pulling the record into array
From there, I'm trying to get the field "name" from my array.
cell.textLabel.text = [NSString stringWithFormat:#"%#", [personInfo objectAtIndex: indexPath.row] retain]
As it seems you have objects in your array, what you may be looking for is the -[NSArray valueForKey:] method (documentation here).
For example:
NSArray *names = [personInfo valueForKey:#"name"];
This should return you an array containing all of the names in the array.
Are you trying to create a 2D Array?. If so you'll need to call objectAtIndex: twice on it in a nested call, but since you're new I'd suggest breaking down to a few lines so you can see more clearly what is happening.
Also, theres heaps of good code snippets on google for dealing with NSArray and table view.
Please check that if you delcare your array in #interface file as
//////.h
NSArray *personInfo;
#property(nonatomic ,retain) NSArray personInfo;
and then
in #implementation file
add this line
#synthesize personInfo;
hope it works

Proper way of creating new objects which are copies of NSDictionary and NSArray objects defined in app delegate

I am wondering what the correct way is to make a copy of an object defined in the app delegate or a singleton object. In short, I am making an app which requires a user to login. This login view is just a modal view controller on top of the 'real' app, which consists of a tabbarcontroller, plus some tableview controllers. After a successful login, there is send a data request to a remote server, and the modal view controller is dismissed, revealing the tabbar controller and table views holding the XML data. To parse the incoming data, I have created a singleton object named DataParser, which has interface
...
#interface DataParser : NSObject {
// Data objects that hold the data obtained from XML files
NSMutableDictionary *personnel;
NSMutableDictionary *schedule;
NSMutableDictionary *today;
}
#property (nonatomic, retain) NSMutableDictionary *personnel;
#property (nonatomic, retain) NSMutableDictionary *schedule;
#property (nonatomic, retain) NSMutableDictionary *today;
...
Now in these dictionaries I store (mutable) dictionaries and arrays holding NSString objects with the parsed XML data. Since I do not want to modify these original objects holding the parsed data (that is to say, I only want to modify them at the login stage, but not in any of the tableview controllers), I am creating a new dictionary object which holds a copy of the content of one of the dictionaries above in each tableview controller. So for instance, in the loadView of a view controller called ScheduleViewController I have
...
#interface ScheduleViewController : UITableViewController {
NSDictionary *copyOfSchedule;
}
#property (nonatomic, retain) NSDictionary *copyOfSchedule;
...
#end
#implementation ScheduleViewController
#synthesize copyOfSchedule;
- (void)loadView {
[super loadView];
DataParser *sharedSingleton = [DataParser sharedInstance];
self.copyOfSchedule = [NSDictionary dictionaryWithDictionary:sharedSingleton.schedule];
}
...
Now this seems to work fine. The only difficulty arises however, when the user 'logs out', which entails popping the login modal view controller back on the stack. When the user presses the login button again, then a new XML data request is send to the server and the dictionaries in the singleton object get refreshed with the (new) data (I check if they contain any data, if so I call removeAllObjects before filling them up again with newly parsed data). At this point the dictionaries in all view controllers should be updated too, however I am not quite sure how to go about this the right way. I have noticed that loadView is not always called again in this case and so to this end I have added the same code as above in loadView to every viewWillAppear method. After navigating back and forth between the different views or navigating back and forth between child views of a tableview a couple of times, I receive an EXC_BAD_ACCESS error however. I suspect this has to do with not properly retaining the copies of the original dictionaries, but I don't seem to be able to find a solution around this. Instead of using dictionaryWithDictionary, which I suspect is not the right way to go anyway, I also tried a different approach, where instead of using objects of type NSDictionary in ScheduleViewController I use NSMutableDictionary. So:
...
#interface ScheduleViewController : UITableViewController {
NSMutableDictionary *copyOfSchedule;
}
#property (nonatomic, retain) NSMutableDictionary *copyOfSchedule;
...
#end
#implementation ScheduleViewController
#synthesize copyOfSchedule;
- (void)loadView {
[super loadView];
DataParser *sharedSingleton = [DataParser sharedInstance];
self.copyOfSchedule = [[NSMutableDictionary alloc] initWithDictionary:sharedSingleton.schedule];
}
- (void)viewWillAppear {
DataParser *sharedSingleton = [DataParser sharedInstance];
[self.copyOfSchedule removeAllObjects];
[self.copyOfSchedule addEntriesFromDictionary:sharedSingleton.schedule];
[self.tableView reloadData];
}
...
But this doesn't get rid of the EXC_BAD_ACCESS errors. To make a very long story short: what would be the best way to go about making independent copies of objects defined in a singleton object or app delegate and which can be dynamically updated at request? Since I am already rather into the project and lots is going on, I realize that my question may be a bit vague. Nonetheless I hope there is somebody who could enlighten me somehow.
Deep copies are often made recursively. One way to do it would be to add -deepCopy methods to NSDictionary and NSArray. The dictionary version might go like this:
- (NSDictionary*)deepCopy
{
NSMutableDictionary *temp = [self mutableCopy];
for (id key in temp) {
id item = [temp objectForKey:key];
if ([item respondsToSelector:#sel(deepCopy)] {
// handle deep-copyable items, i.e. dictionaries and arrays
[temp setObject:[item deepCopy] forKey:key]
}
else if ([item respondsToSelector:#(copy)]) {
// most data objects implement NSCopyable, so will be handled here
[temp setObject:[item copy] forKey:key];
}
else {
// handle un-copyable items here, maybe throw an exception
}
}
NSDictionary *newDict = [[temp copy] autorelease];
[temp release]
return newDict;
}
I haven't tested that, so be a little careful. You'll want to do something similar for NSArray.
Note that views are not copyable.
It is quite a typical pattern that you build an array or dictionary with some code, so clearly it must be mutable while you add bits to it, and when you're done you don't want it ever to change. To do this:
Have a property like
#property (...) NSArray* myArray;
When you calculate the contents of myArray, use a mutable array to build it, like
NSMutableArray* myMutableArray = [NSMutableArray array];
When you're done building the array, just use
self.myArray = [NSArray arrayWithArry:myMutableArray];

Resources