This should be simple. All I want to do is randomize an NSArray. I found this neat little plugin to do just that called "shuffledArray". https://github.com/bryanluby/NSArray-Shuffle
So I should be finished right now. I imported NSArray+Shuffle.h
#import "NSArray+Shuffle.h"
I added a shuffledArray interface:
#interface TipCollectionViewController ()
{
AJNotificationView *panel;
NSString * query;
// CLLocationManager * locationManager;
NSMutableArray * _entries;
// NSArray *shuffledArray;
int page;
int c_page;
NSArray *mostPopular;
NSArray *ranDom;
NSRange blueRange;
//int pageNum;
//NSString *phpLink;
NSMutableData *responsePlaceData;
}
-(NSMutableArray *)shuffledArray;
#property (nonatomic, weak) IBOutlet CollectionLayout *tipsLayout;
#property (nonatomic, strong) UIImageView *menuImage;
//#property SESpringBoard *board2;
#property (nonatomic, retain) NSMutableArray *itemCounts;
#end
...yet when I try to randomize an Array:
ranDom = [_entries shuffledArray];
It tells me that no NSMutableArray interface called shuffledArray exists.
Any idea where I'm going wrong? This is giving me a headache.
I'll do the honors...
FIRST off the guy's code, instructions, and github page are all wrong.
ranDom = [_entries shuffledArray];
...was never going to work.
Because in the source code his method is actually:
bjl_shuffledArray
So...
ranDom = [_entries bjl_shuffledArray];
works.
The second problem was actually my fault.
I was writing to:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
...when I should've been writing to:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
So the solution is:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
{
ranDom = [_entries bjl_shuffledArray];
mostPopular = [[_entries reverseObjectEnumerator]allObjects];
if (isChangeData){
NSLog(#"Most Popular");
dataLand = mostPopular;
}
else if(isChangeData2){
NSLog(#"Random");
dataLand = ranDom;
}
else{
NSLog(#"All");
dataLand = _entries;
}
Place *p = [dataLand objectAtIndex:indexPath.item];
}
With "dataLand" being another NSArray I came up with.
Now it works! I really need to start getting some more sleep.
Related
I'm really lost as to what is happening here.
I am basically trying to pass a variable between two classes but it doesn't even get to that point for one of these variables.
I have two Strings and two buttons declared.
#property (nonatomic, strong) NSString *qm;
#property (nonatomic, strong) NSString *m;
#property (nonatomic, strong) IBOutlet UIButton *mBtn;
#property (nonatomic, strong) IBOutlet UIButton *qmBtn;
I synthesise the strings..
#synthesize qm;
#synthesize m;
Initialise the strings...
- (void)viewDidAppear:(BOOL)animated{
qm = #"0";
m = #"0";
}
And these methods reassign the new variable based on the selected button on the view (I've definitely made sure to link the buttons to their corresponding variables and methods from the view)
- (IBAction)mPressed:(id)sender {
m = #"1";
}
- (IBAction)qmPressed:(id)sender {
qm = #"1";
NSLog(#"This value%#", qm);
}
The NSLog prints the value 1, which is what I want
When the program enters the segue part. Things don't work as planned...
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Here:%#", qm);
if([m isEqualToString: #"1"]){
QMMPOpViewController *mpOp = [segue destinationViewController];
NSLog(#"test 1:%#",self.qm);
mpOp.qm = self.qm;
mpOp.selectedQuiz = self.selectedQuiz2;
NSLog(#"This value2%#", qm);
NSLog(#"This value3%#", m);
}
else if([qm isEqualToString: #"1"]){
QMMPOpViewController *mpOp = [segue destinationViewController];
NSLog(#"test 2:%#",self.qm);
mpOp.qm = self.qm;
mpOp.selectedQuiz = self.selectedQuiz2;
NSLog(#"This value2%#", qm);
NSLog(#"This value3%#", m);
}
else{
QMSPController *tableVC = [segue destinationViewController];
tableVC.selectedQuiz = self.selectedQuiz2;
}
}
I have changed the value of qm; the NSLog outputs the value 0 instead of the new variable, 1. So therefore ([qm isEqualToString: #"1"]) is never called.
This is so simple yet it still doesn't work despite my attempts to debug the issue. The m value executes fine. Though identical in their means of operation. For some reason the other one does not.
Maybe I'm missing something blatantly obvious or basic. Or if someone could let me know what could possibly be going on here that would be greatly appreciated.
I have this piece of code below and I'm trying to add Objects(String elements) to an array, problem is that every time I'm out its adding's method, it goes to nil, it doesn't retain the objects.
I know I'm doing wrong, even that I already tried lot of combinations and variations, even with my own constructor _MyArray etc etc, same result... it works, but not further...
Could you help me please?
#interface ArraysModel()
#property (nonatomic, retain) NSMutableArray *MyArray;
#end
#implementation ArraysModel
#synthesize MyArray;
-(void)AddObjectToTheList:(NSString *)object {
if(!MyArray) MyArray = [[NSMutableArray alloc] init];
[MyArray addObject:object];
NSLog(#"%#",self.MyArray);
NSLog(#"Object added %u",[self.MyArray count]);
}
-(NSMutableArray *)ObjectList {
return self.MyArray;
NSLog(#"%#",self.MyArray);
NSLog(#"Object added %u",[self.MyArray count]);
}
#end
The header is like this:
#interface ArraysModel : NSObject
-(void)AddObjectToTheList:(NSString *)object;
And here is my call from my ViewController:
- (IBAction)AddToTheList {
ArraysModel *MyObjectToAdd = [[ArraysModel alloc] init];
[MyObjectToAdd AddObjectToTheList:TextArea.text];
[self.view endEditing:YES];
Well, there's your problem -- you're alloc init'ing a new instance of ArraysModel, and therefore a new array with every call. You need to create a strong reference to your instance, and check for whether it exits, and only init if it doesn't.
In the .h:
#property (strong, nonatomic) ArraysModel *myObjectToAdd;
in the .m:
-(IBAction)AddToTheList {
if (! self.myObjectToAdd) {
self.myObjectToAdd = [[ArraysModel alloc] init];
}
[self.myObjectToAdd AddObjectToTheList:TextArea.text];
[self.view endEditing:YES]
}
I have a subclass of UITableViewController, and I init the subclass with a NSMutableArray of another custom class:
#import <UIKit/UIKit.h>
#import "NUBCheckpointModel.h"
#interface NUBUserCheckpointModel : NSObject
#property (nonatomic,assign) NSString* objId;
#property (nonatomic,assign) NSString* userId;
#property (nonatomic,assign) NSString* checkpointId;
#property (nonatomic,assign) NSDate* dateAdded;
#property (nonatomic,assign) NUBCheckpointModel* checkpoint;
+ (NUBUserCheckpointModel*) fromJson: (NSString*)json;
#end
This array that is generated from another ViewController, gets passed into this subclassed TableViewController, of which contain this property
#property (nonatomic,retain) NSMutableArray* userCheckpointData;
This property is set like this:
- (id)initWithFrame: (CGRect)frame withType: (TableType)typeOfTable fromParent: (UIViewController*)parent data: (NSMutableArray*)ucpData
{
self = [self init];
if (self) {
self.tableView = [[UITableView alloc] initWithFrame:frame];
self.parentController = parent;
self.userCheckpointData = ucpData;
[self styleTable];
[self addPullToRefreshHeader];
typeCategory = typeOfTable;
}
return self;
}
All is fine up to this part, and any manipulation including trying to get an object from the array works fine. I tested it.
The code I used to test the array is:
NUBUserCheckpointModel* model = [self.userCheckpointData objectAtIndex:0];
NSLog(model.objId);
However, this very same code, when used here:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Gives me exc_bad_access. May I know why this happens? I can't seem to figure out why. I'm using ARC btw. Thank you.
While adding the property, you need to take care of the memory management. For string, it is not good practice to set assign property.
Instead , do as following,
#property (nonatomic,copy) NSString* objId;
#property (nonatomic,copy) NSString* userId;
#property (nonatomic,copy) NSString* checkpointId;
#property (nonatomic,retain) NSDate* dateAdded;
#property (nonatomic,retain) NUBCheckpointModel* checkpoint;
I am starting my first Cocoa Project. And I have a serious (for me) but maybe easy problem (for you) to solve and I need some direction where to start.
The short description: I have built a class "PortConnection.h" who writes all ports found by an external class (AMSerial.h) into an array when the function -listPorts is called. Here is the code for the PortConnection.h
#import <Cocoa/Cocoa.h>
#import "AMSerialPortList.h"
#import "AMSerialPortAdditions.h"
#import "AMSerialPort.h"
#interface PortConnection : NSObject {
#private
AMSerialPort *port;
NSMutableArray *portArray;
}
- (void)listDevices;
#property (nonatomic, retain) NSMutableArray *portArray;
#property (nonatomic, retain) AMSerialPort *port;
#end
and following the PortConnection.m
#import "PortConnection.h"
#import "AMSerialPortList.h"
#import "AMSerialPortAdditions.h"
#import "AMSerialPort.h"
#implementation PortConnection
#synthesize portArray;
#synthesize port;
- (void)listDevices
{
// get an port enumerator
NSEnumerator *enumerator = [AMSerialPortList portEnumerator];
AMSerialPort *aPort;
while ((aPort = [enumerator nextObject]))
{
// Add Devices to Array
[portArray addObject:[aPort bsdPath]];
}
}
So far it is perfectly working.
Now my questions
I have implemented an tableView in the GUI for display the results of the method called above. This file is called "PortTableViewController.h" and is the datasource for my TableView.
Here is the .h file
#import <Foundation/Foundation.h>
#import "PortConnection.h"
#interface PortTableViewController : NSObject <NSTableViewDataSource> {
#private
IBOutlet NSTableView *portTableView;
}
#property (assign) IBOutlet NSTableView *portTableView;
#end
and here is the .m file:
#import "PortTableViewController.h"
#import "PortConnection.h"
#implementation PortTableViewController
#synthesize portTableView;
#pragma mark -
#pragma mark TableView Delegates
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
PortConnection *portConnection = [[PortConnection alloc] init];
[portConnection listDevices];
return [portConnection.portArray count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
??????? I DO NOT HAVE A CLUE HOW TO ACCESS THE ARRAY IN PORTCONNECTION.M CORRECTLY
}
#end
QUESTIONS:
1) When having a look on the TableViewDataSourceDelegates how do I access the filled portArray in the PortConnection.m class correctly. It doesn't seem to work the way I do it.
2) Do I have to create an Object from Portconnection.h every time I want to retrieve Data from it in a tableviewdelegate method?
I am really thankful for every kind of help! I want to learn something.. and I really appreciate your support! Thanks.. for question in order to help me, don't hesitate. I really appreciate it....
Thanks
Sebastian
A simple fix is to have your table view controller declare an instance variable that holds a PortConnection instance. This instance is created and sent -listDevices in -init, it is used by all methods in your table view controller (which means that all methods refer to the same PortConnection instance), and released in -dealloc.
For example:
PortTableViewController.h
#import <Foundation/Foundation.h>
#import "PortConnection.h"
#interface PortTableViewController : NSObject <NSTableViewDataSource> {
#private
IBOutlet NSTableView *portTableView;
PortConnection *portConnection;
}
#property (assign) IBOutlet NSTableView *portTableView;
#end
PortTableViewController.m
#import "PortTableViewController.h"
#import "PortConnection.h"
#implementation PortTableViewController
#synthesize portTableView;
#pragma mark -
#pragma mark TableView Delegates
- (id)init {
self = [super init];
if (self) {
portConnection = [[PortConnection alloc] init];
[portConnection listDevices];
}
return self;
}
- (void)dealloc {
[portConnection release];
[super dealloc];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
return [portConnection.portArray count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
return [portConnection.portArray objectAtIndex:row];
// or whatever behaviour provides an object value for the column/row
}
#end
If you don't want to create a field in every delegate you could create a static variable in PortConnection which holds the array. Initially the array is nil and on the first call to get the ports you create the list if needed.
In the implementation file:
static NSMutableArray *portArray;
+ (NSArray) listPorts {
if(portArray != nil)
return (NSArray *)portArray;
NSEnumerator *enumerator = [AMSerialPortList portEnumerator];
AMSerialPort *aPort;
portArray = [[NSMutableArray alloc] init];
while ((aPort = [enumerator nextObject])) {
// Add Devices to Array
[portArray addObject:[aPort bsdPath]];
}
}
This of course depends on how often the portArray will change, if it's often I would probably just generate it every time.
You could also do a getPortArray which calls generatePortArray if portArray is nil
You should only need a single PortConnection instance, but your table view controller will somehow need to know about it. It could be that the PortTableViewController creates and owns the PortConnection object, or it could be that some other object, like the app delegate or another controller creates it.
In the former case, it's trivial... the PortTableViewController creates the PortConnection instance, and therefore it has a reference to it and can access its portArray property at well.
In the latter case, things aren't much more complicated: the object that creates the PortController should give the PortTableViewController a pointer to the PortController. The PortTableViewController should then retain the PortController and stash the pointer in an instance variable so that it can access the portArray property as needed.
**Note: I have updated the code based off of aroth's suggestions - however it is still crashing. The code in the below post is the updated code.
I am trying to create an iPhone app based off of the table-view XCode template (XCode 4). The table view gets populated with the correct data in the proper order - however when I go to scroll through the table the app crashes (sometimes I can scroll through 5 or 10 more cells, sometimes it freezes right away). The table view is being fed from 'Artist' objects within an NSArray which is an IVAR of another 'iPodLibraryParser' object. I believe the problem is that the 'iPodLibraryParser' object is being released prematurely - but I don't understand why.
I have created an iPodLibraryParser object with the following header file:
#import <Foundation/Foundation.h>
#import <MediaPlayer/MediaPlayer.h>
#import <CoreLocation/CoreLocation.h>
#import "ArtistClass.h"
#interface iPodLibraryParser : NSObject {
//Location stuff
CLLocationManager *locationManager;
IBOutlet UITextField *latitudeTextField;
IBOutlet UITextField *longitudeTextField;
IBOutlet UILabel *latitudeLabel;
IBOutlet UILabel *longitudeLabel;
//Music Library Stuff
NSString *currentArtist;
NSString *currentAlbum;
NSMutableArray *artistArray;
NSMutableArray *sortedArtistArray;
}
#property (nonatomic, retain) NSMutableArray *sortedArtistArray;
-(void)parseiPodLibrary;
-(id) initializeiPodLibraryParser;
#end
The relevant code in the .m file of this Class:
#implementation iPodLibraryParser
#synthesize sortedArtistArray;
-(id) initializeiPodLibraryParser{
[super init];
sortedArtistArray = [[NSMutableArray alloc] initWithObjects:nil];
return self;
}
-(void)parseiPodLibrary{
.....
NSArray *sortingArray = [[NSArray alloc] initWithObjects:artistTrackCountSorter,nil];
NSArray *tempSortedArray = [artistArray sortedArrayUsingDescriptors:sortingArray];
[sortedArtistArray removeAllObjects];
[sortedArtistArray addObjectsFromArray:tempSortedArray];
}
Artist object header:
#import <UIKit/UIKit.h>
#import "iPodLibraryParser.h"
#interface ArtistClass : NSObject {
NSString *artistName;
int numberOfTracks;
id artistClassViewController;
}
-(id) initializeArtistObjectWithDocument:(id)myDocument withArtist:(NSString*) artist;
#property (nonatomic, retain) NSString *artistName;
#property (nonatomic, assign) int numberOfTracks;
#end
Table View Controller (called RootViewController from the template being used)
Header:
#import <UIKit/UIKit.h>
#import "iPodLibraryParser.h"
#import "ArtistClass.h"
#interface RootViewController : UITableViewController {
iPodLibraryParser *iPodLibrary;
}
#property (nonatomic, retain) iPodLibraryParser *iPodLibrary;
#end
Relevant code
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(#"In viewDidAppear");
iPodLibrary = [[iPodLibraryParser alloc] initializeiPodLibraryParser];
[iPodLibrary parseiPodLibrary];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"there are %i artists in the array", [[iPodLibrary sortedArtistArray] count]);
return [[iPodLibrary sortedArtistArray] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"in tableView blah");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
NSLog(#"getting row: %i",indexPath.row);
cell.textLabel.text = [[[iPodLibrary sortedArtistArray] objectAtIndex:indexPath.row] artistName];
return cell;
}
The error is at this line:
cell.textLabel.text = [[[iPodLibrary sortedArtistArray] objectAtIndex:indexPath.row] artistName];
I tried creating an array with Artist objects that I created within the RootViewController - and that works perfectly (can scroll the entire table with no crashes)
Thanks again!
--Edit:
It is interesting to note that I get different errors at different times:
Most of the times it's just EXC_BAD_ACCESS at the line:
cell.textLabel.text = [[[iPodLibrary sortedArtistArray] objectAtIndex:indexPath.row] artistName];
Sometimes it's:
-[UIAutoRotatingWindow isEqualToString:]: unrecognized selector sent to instance 0x1baa80
And another had to do with an unrecognized RGB Selector (very strange).
You problem is when you do this:
sortedArtistArray = [artistArray sortedArrayUsingDescriptors:sortingArray];
The sortedArrayUsingDescriptors method is returning an autoreleased object, so you shouldn't be surprised when it gets released on you without warning.
Moreover, because your init does:
sortedArtistArray = [[NSArray alloc] init];
...and because you don't release it before you assign to it, your code is leaking NSArray instances. I would suggest the following revisions:
Make sortedArtistArray an NSMutableArray*, like:
NSMutableArray* sortedArtistArray;
Don't overwrite the array reference in parseiPodLibrary. Instead just copy the sorted dataset into the mutable array, like:
-(void)parseiPodLibrary{
//.....
NSArray* temp = [artistArray sortedArrayUsingDescriptors:sortingArray];
[sortedArtistArray removeAllObjects];
[sortedArtistArray addObjectsFromArray:temp];
}
Don't call [iPodLibrary retain]; in viewDidAppear. You've already called alloc/init on it, so there is no need to retain it again.
Ensure that you call [iPodLibrary release]; in viewWillDisappear, and [sortedArtistArray release]; in dealloc so that you don't leak memory.
I think it's much more likely that your iPodLibrary variable is over-released than that it's the array. You should troubleshoot by splitting your code into a few lines and seeing where it fails:
NSArray *artistArray = [iPodLibrary sortedArtistArray];
Artist *artist = [artistArray objectAtIndex:indexPath.row];
NSString *name = [artist artistName];
cell.textLabel.text = name;
Is it possible that your implementation of initializeiPodLibraryParser returns an autoreleased object? It shouldn't, as that violates the convention. But it would make sense that that would lead to this problem.
When you call this:
iPodLibrary = [[iPodLibraryParser alloc] initializeiPodLibraryParser];
you're directly assigning the iPodLibrary ivar, so its mutator isn't called and it doesn't matter that the property is marked as retain. If you think it's being implicitly retained, it's likely you're over-releasing it somewhere else. I find you'll understand your own memory management if you use this style to assign properties:
iPodLibraryParser *parser = [[iPodLibraryParser alloc] initializeiPodLibraryParser]; // retain count should be 1 if not autoreleased
[self setIpodLibrary:parser]; // retain count is now 2
[parser release]; // retain count is now 1, will go to zero when you release it in dealloc or viewDidUnload
Finally, I'd move your iPodLibrary initialization from viewDidAppear to viewDidLoad:. That's where you should be initializing your view. And you should be cleaning up anything you initialize there in viewDidUnload, which will be called in a low memory situation.