I am trying to create a dynamic top menu.
I have to get some data from a json request and display this data in one of the sections of the top menu. I'm new in Objective-C. I also tried with NSMutableArrays and I had an error. Only one MutableArray and I can show the top menu. I am following this third party framework for top menu “https://github.com/dopcn/DOPNavbarMenu”.
- (DOPNavbarMenu *)menu {
if (_menu == nil) {
[strArray objectAtIndex:0];
NSLog(#"Random Selection is:%#",strArray);
_menu = [[DOPNavbarMenu alloc] initWithItems:#[strArray] width:self.view.dop_width maximumNumberInRow:_numberOfItemsInRow];
_menu.backgroundColor = [UIColor blackColor];
_menu.separatarColor = [UIColor whiteColor];
_menu.delegate = self;
}
return _menu;
}
-(void)loadData
{
strResponse=[dictionary objectForKey:#"data"];
strMsg=[strResponse valueForKey:#"Text"];
NSLog(#“string message is :%#",strMsg);
NSLog(#"String Response is :%#",strResponse);
NSLog(#"Text Response is: %#",strMsg);
strArray = [[NSMutableArray alloc] init];
[strArray addObject:strMsg];
NSLog(#"Array values are - %#", strArray);
}
Array values are: Life Style,Care Plans,Trackers/Diaries,Questionnaires/Assessments.
but i got exception like this:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]'
Ok, per your comment
but i want to call menu method before loadData finishes
the issue lies here :
_menu = [[DOPNavbarMenu alloc] initWithItems:#[strArray] width:self.view.dop_width maximumNumberInRow:_numberOfItemsInRow];
Before loadData is run, I assume that strArray is nil. This causes this part #[strArray] to fail - this creates a new array with strArray as its only element, which cannot be nil.
I also assume that you wanted to rather pass strArray itself there, not wrap it in another array.
Now, if you call menu before populating strArray in loadData, there will likely be no items present in the menu, unless you have a way to update it with new items after loadData finishes.
To summarise : to fix your immediate issue, you should change the above line to this :
_menu = [[DOPNavbarMenu alloc] initWithItems:strArray width:self.view.dop_width maximumNumberInRow:_numberOfItemsInRow];
which should work, but there won't be any items present in the menu, because of reasons explained above.
Related
I am using an NSArray to load objects into my UICollectionView. The UICollectionView has a UIPageViewController associated with it where I am grabbing the index for each page. Depending on what page you are on, I want to load different objects.
I try to do that using the following:
NSDictionary *dictionary = [[NSDictionary alloc] init];
if (self.index == 0) {
dictionary = [self.imageArray objectAtIndex:indexPath.row];
} else if (self.index == 1) {
dictionary = [self.imageArray objectAtIndex:12 + indexPath.row];
NSLog(#"%#", self.imageArray);
} else if (self.index == 2) {
dictionary = [self.imageArray objectAtIndex:24 + indexPath.row];
}
Where self.index is the page you are on.
However, I keep getting the following crash:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 48 beyond bounds [0 .. 47]'
However, my array does have 48 objects. There are 12 objects loaded on each page.
Does it have anything to do with me setting the dictionary each time? Only thing I could think of....
Help would be appreciated.
Instead of using those ugly ifs and twisted logic, try to structure your model better. One way of doing this would be to have an array of arrays: each page an array of images. You'd know the pages count from the model and accessing the right image would be as simple as self.images[self.index][indexpath.row] You could also use an UIcollectionview with each page a section.
I am getting this error when trying to add the NSString object named object to my array :
erminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x7fc48ae52ba0'
Not sure why this is so. I was originally using NSArray to changed it to NSMutableArray but I am still having problems with it. Code is below:
-(NSMutableArray *)getReplyArrayForMessage: (NSString *)message {
//get the array
NSMutableArray *replies = [self.messageDictionary objectForKey:message];
NSLog(#"%#",replies);
//if no replies we init the base set
if([replies count]==0) {
//get the base array
//this also works if a key just isn't in the dictonary
return replies=[self getBaseArray];
}
else {
//add the other message
NSString *object = #"Send a different message";
[replies addObject:object];
return replies;
}
}
If anyone could give me a pointer to why this is happening I would appreciate it. Noob here.
The array is immutable (NSArray), not mutable (NSMutableArray). You can create a mutable array from an immutable array using mutableCopy:
NSMutableArray *replies = [[self.messageDictionary objectForKey:message] mutableCopy];
I know this from the exception text:
-[__NSArrayI addObject:]: unrecognized selector sent to instance ...
^^^^^^^^^^
EDIT I've missed off some important information from my original answer.
Having used mutableCopy you now have a copy of the array and the original array (from self.messageDictionary objectForKey:message) will remain unchanged after you add your element. This is almost certainly not what you intended.
As I've mentioned in the comments below, you probably want to create a custom object to hold these details (or an array of custom objects) that should be created from the message dictionary as soon as you receive it. The effort required to create a custom object will pay for itself tenfold in the long term.
You are trying to add an NSString to an NSArray (which looks like an NSMutableArray) since you initialized it as one. This means that the object that you store in your messageDictionary is actually of type NSArray, and not NSMutabelArray. So, assigning it to an object of type NSMutableArray won't actually change its type and make it mutable.
It's an easy fix:
NSMutableArray *replies = [[NSMutableArray alloc] initWithArray:(NSArray *) [self.messageDictionary objectForKey:message]];
Or you can go with mutableCopy (as suggested by #trojanfoe) which is a shortcut but will lead to the same result.
I can tell because the error message says -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x7fc48ae52ba0'. Notice the I at the end of __NSArrayI, this means that this array is actually immutable, so you can't add objects to it.
So at runtime I initialize my NSMutableDictionary, and then when the user clicks on certain buttons, the app needs to get the name of this button and this name will be the key. Then he will click on another button, and this button's name will be put into an array, and the array will become the value of the first button name's key. However, later the user will keep doing this, and if he ends up clicking on a button that already is a value in the dictionary, then the second button he presses must be added to the array already associated with that key. Here is my code so far.
closestBeaconsDictionary is the main dictionary. closestBeaconName is a variable that makes up the keys, and pinNumberName is the value that must be put into an array. closestBeaconName and pinNumberName are constantly changing based on what buttons the user presses.
//first, check to see if the key already exists. If not, then add the key to
//closestBeaconsDictionary and then create an array and add this array to the dictionary
//and then add pinNumberName to this array.
if ([closestBeaconsDictionary objectForKey:pinNumberName] == nil)
{
NSMutableArray *closestPinsToBeacon = [[NSMutableArray alloc] init];
[closestPinsToBeacon addObject:pinNumberName];
[closestBeaconsDictionary setObject:closestPinsToBeacon forKey:closestBeaconName];
}
else
{
//what do I do here?? How do I access the dictionary that is at key:pinNumberName
//and then add an object to it?
}
So, my question is basically what do I put in the else statement? I'm confused because isn't closestPinsToBeacon basically destroyed after the block of code runs?
Try this:
if ([closestBeaconsDictionary objectForKey:pinNumberName] == nil)
{
NSMutableArray *closestPinsToBeacon = [[NSMutableArray alloc] init];
[closestPinsToBeacon addObject:pinNumberName];
[closestBeaconsDictionary setObject:closestPinsToBeacon forKey:closestBeaconName];
}
else
{
NSMutableArray *arr = [[NSMutableArray alloc] init];
arr = [[closestBeaconsDictionary objectForKey: closestBeaconName] mutableCopy];
[arr addObject:pinNumberName];
[closestBeaconsDictionary removeObjectForKey: closestBeaconName];
[closestBeaconsDictionary setObject:arr forKey: closestBeaconName];
}
Hope this helps.. :)
So here's the case:
I wish to fill the prototype cells with the names of the friends selected in the UIPickerView over there. I have programatically filled the picker with the correct data, and set its properties using the delegate functions.
The "New Game Friends View" you see here has its own viewcontroller subclass, as has the table view, which I attempt to embed into a UIView on the "New Game Friends View".
I have in many ways tried to add data to the prototype cells, but with no luck. Here's my current addBtnClicked function:
- (IBAction)addBtnClicked:(id)sender {
WHGFriendTableViewController* tabView = (WHGFriendTableViewController*) [[self childViewControllers] objectAtIndex:0];
NSInteger row = [friendPicker selectedRowInComponent:0];
[[tabView selectedFriends] addObject:[[self friendList] objectAtIndex:row]];
}
This pretty much crashes my app. Whenever I hit the Add Friend button, the iPhone sends an abort signal, and gives back this message:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController
selectedFriends]: unrecognized selector sent to instance 0x978d530'
Any help with this problem is very appreciated. Thanks in advance!
Do you have a property called selectedFriends on your New Friends view controller?
If the answer is yes try:
- (IBAction)addBtnClicked:(id)sender {
WHGFriendTableViewController* tabView = (WHGFriendTableViewController*) [[self childViewControllers] objectAtIndex:0];
NSInteger row = [friendPicker selectedRowInComponent:0];
[[self selectedFriends] addObject:[[self friendList] objectAtIndex:row]];
}
If selectedFriends is a property of WHGFriendTableViewController, you should create a public method that adds a friend to the Mutable Array and call it from addBtnClicked IBAction.
Some information about the way I am saving my data: I have an array of View Controllers that are added and deleted by the user (this is basically a note taking app and the View Controllers are folders). The View Controllers have several dynamic properties that the app needs to save as well as the notes array within them, and then the Note objects themselves have a few properties that need to be saved. The View Controllers and the Notes both of course have the proper NSCoding stuff, this is the one on the View Controller for example:
- (void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:self.folderName forKey:#"lvcTitle"];
[encoder encodeObject:[NSNumber numberWithInt:self.myPosition] forKey:#"myPosition"];
[encoder encodeObject:self.notes forKey:#"notes"];
}
- (id)initWithCoder:(NSCoder *)decoder {
self.folderName = [decoder decodeObjectForKey:#"lvcTitle"];
NSNumber *gottenPosition = [decoder decodeObjectForKey:#"myPosition"];
int gottenPositionInt = [gottenPosition intValue];
self.myPosition = gottenPositionInt;
self.notes = [decoder decodeObjectForKey:#"notes"];
return self; }
The array of Controllers belongs to a Singleton class. NSCoding is pretty confusing to me even though it's considered to be simple stuff, but so far I've had success with only telling the Singleton to save the Controllers array - which then (successfully) saves all of the contained properties of the View Controllers, their properties and all of the Notes' properties as well. Here is the code in the Singleton:
- (void) saveDataToDisk:(id)object key:(NSString *)key {
NSString *path = [self pathForDataFile];
NSMutableDictionary *rootObject;
rootObject = [NSMutableDictionary dictionary];
[rootObject setValue:object forKey:key];
[NSKeyedArchiver archiveRootObject:rootObject toFile:path]; }
- (void) loadDataFromDisk {
NSString *path = [self pathForDataFile];
NSDictionary *rootObject;
rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
if ([rootObject valueForKey:#"controllers"] != nil) {
self.controllers = [NSMutableArray arrayWithArray:[rootObject valueForKey:#"controllers"]];
firstRun = false;
LabeledViewController *lastOneThere = [self.controllers objectAtIndex:self.controllers.count-1];
lastOneThere.isFolderAddView = TRUE;
}else{
firstRun = true;
}
}
I then call the save method several times in the Folder View Controllers:
[singleton saveDataToDisk];
And this will work well several times, until I randomly get a crash right when the app is loading up. The culprit is heightForRowAtIndexPath:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
Note *currentNote = [self.notes objectAtIndex:indexPath.row];
if (currentNote.associatedCellIsSelected) {
return currentNote.myHeight + NOTE_BUTTON_VIEW_HEIGHT;
}
return NORMAL_CELL_FINISHING_HEIGHT; }
I get the following error:
2012-06-07 08:28:33.694 ViewTry[1415:207] -[__NSCFString associatedCellIsSelected]: unrecognized selector sent to instance 0x8904710
2012-06-07 08:28:33.696 ViewTry[1415:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString associatedCellIsSelected]: unrecognized selector sent to instance 0x8904710'
*** First throw call stack:
I understand that "__NSCFString" and "unrecognized selector sent to instance" means that there is a string somewhere there shouldn't be, as associatedCellIsSelected is a bool. However, if I only return "currentNote.myHeight" in heightForRow, I also get the same __NSCF error with myHeight, which is a float. If I take out heightForRow all together, everything works except for the appropriate height definitions.
BTW, the table view that heightForRowAtIndexPath is referencing is made in loadView AFTER the notes array is made and populated. I just don't understand why this error would only pop up every once in a while (like 5-10 opens, savings, closings and reopenings of app), seemingly random - I cannot find the pattern that causes this behavior. Any pointers?
Sorry for the mess, I'm new to iOS programming and I'm sure I'm doing a lot of things wrong here.
Edit - Also, once the app has crashed, it stays crashed every time I reopen it (unless I disable heightForRow) until I uninstall and reinstall it.
When you see an "unrecognized selector" error and the receiver type is not the kind of object that you coded (in this case __NSCFString instead of Note), the odds are that you have a problem where the object you intended to use has been prematurely released and its address space is being reused to allocate the new object.
The fix depends on tracking down where the extra release is happening (or retain is not happening). If you can show the #property declaration for notes it might shed more light on the situation.
One quick thing to do is choose Product->Analyze from the menu and fix anything it flags. It won't catch everything but it's a good sanity check to start.