Iterate through NS array of obs - iphone

I need to take this data structure, an nsmutablearray, and iterate through each index and print each field into a textfield. every "forward" button increments the data ahead and "backwards" goes back. I am having a really hard time getting this to work properly, does anyone know what im doing wrong. Keep in mind, the object held in the array, called info_holder, is an object that holds 3 strings and one counter:
#import "ZDViewController.h"
#implementation ZDViewController
#synthesize password;
#synthesize count;
#synthesize web;
#synthesize username;
#synthesize header;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
NSMutableArray *array = [[NSMutableArray alloc] init];
info_holder *set1 = [[info_holder alloc] init];
info_holder *set2 = [[info_holder alloc] init];
info_holder *set3 = [[info_holder alloc] init];
info_holder *set4 = [[info_holder alloc] init];
info_holder *set5 = [[info_holder alloc] init];
[set1 SetUser: #"info1"]; //temporary information until big is fixed
[set1 SetPass: #"info2"];
[set1 SetKey: #"webinfo1"];
[set1 SetCount: 0];
[set2 SetUser: #"info3"];
[set2 SetPass: #"info4"];
[set2 SetKey: #"webinfo2"];
[set2 SetCount: 0];
[set3 SetUser: #"info5"];
[set3 SetPass: #"info6"];
[set3 SetKey: #"webinfo3"];
[set3 SetCount: 0];
[set4 SetUser: #"info7"];
[set4 SetPass: #"info8"];
[set4 SetKey: #"webinfo4"];
[set4 SetCount: 0];
[set5 SetUser: #"info9"];
[set5 SetPass: #"info10"];
[set5 SetKey: #"Webinfo5"];
[set5 SetCount: 0];
}
- (void)viewDidUnload
{
[self setHeader:nil];
[self setWeb:nil];
[self setPassword:nil];
[self setCount:nil];
[self setUsername:nil];
[super viewDidUnload];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
- (IBAction)increment:(id)sender {
if(username.text==#"test")
username.text=#"test2";
else
username.text=#"test";
//this should print a new username NSSTRING, wedsite NSTRING, password NSTRING and INEGER counter, heald in the info_holder object, incremented per click backwards
}
- (IBAction)decrement:(id)sender {
}
- (IBAction)Inc:(id)sender {
}
- (IBAction)textFieldDoneEditing:(id)sender {
[sender resignFirstResponder];
}
- (IBAction)backgroundTap:(id)sender {
[web resignFirstResponder];
[username resignFirstResponder];
[count resignFirstResponder];
[password resignFirstResponder];
}
#end
and my main is:
#import <UIKit/UIKit.h>
#import "ZDAppDelegate.h"
#import "info_holder.h"
int main(int argc, char *argv[])
{
#autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([ZDAppDelegate class]));
}
}

- (IBAction)forwards:(id)sender {
//this should print a new username NSSTRING, wedsite NSTRING, password NSTRING and INEGER counter, heald in the info_holder object, incremented per click forward
for(int i=0;i<your_array.count;i++){
username.text=[your_array objectAtIndex:i];
password.text=[your_array objectAtIndex:i];
key.text.text=[your_array objectAtIndex:i];
}
}
Note-1: I assume your texrfield names as username, password and key
Note-2: Your question is too long an i think no one will read so many code to find your matter. Just share what you need .

First, Class names should start in Caps and method names should start in lower case.
Second, your setters in info_holder class (which should be InfoHolder) have potential issues.
an example setter should look like:
- (void)setUser:(NSString *)username
{
[username retain];
[uname release];
uname=username;
}
You didn't state what's not working, but one problem is that you're not retaining those strings.
BASED ON COMMENTS
You need to declare logins a property.
in ZDViewController.h
#interface ZDViewController : UIViewController
#property (strong, nonatomic) NSMutableArray *logins;
Then in ZDViewController.m
#implementation ZDViewController
#synthesize logins;
.
.
.
- (void)viewDidLoad {
logins = [NSMutableArray array];
.
.
.
}
Then you can access self.logins from anywhere in your class

did you stored your info_holder objects into the NSMutableArray instance, If so then you can access the element(info holder instances in your case) of mutable array by either one of the below method,for(ClassName *tmp in _arrayName){ tmp.property1;tmp.property2;..... }or if you want it as index specific for(int index=0;index<[_arrayName count];index++){ ClassName *tmp = [_arrayName objectAtIndex:index];tmp.property1;tmp.property2;.....}. I exactly can't understand your problem but from your writings i guess thee above can be the solution. If not let me know your question , if this certainly helped you then accept the answer. Note: As #dbrajkovic suggest , always follow the naming convention in your programs, that give more flexible readability.

Related

Custom KalDataSource I tried to implement it but I'm getting an error

I try using a custom kal datasource for my calendar. I succeeded in getting the data, and when I tried to run it I keep getting this error:
-[NSNull cc_componentsForMonthDayAndYear]: unrecognized selector sent to instance 0x2823fb8
My code
// KalParseDataSource.m
#import "KalParseDataSource.h"
#import <Parse/Parse.h>
#implementation KalParseDataSource
static BOOL IsDateBetweenInclusive(NSDate *date, NSDate *begin, NSDate *end)
{
return [date compare:begin] != NSOrderedAscending && [date compare:end] != NSOrderedDescending;
}
- (id)init
{
if ((self = [super init])) {
items = [[NSMutableArray alloc] init];
events= [[NSMutableArray alloc] init];
}
return self;
}
#pragma mark UITableViewDataSource protocol conformance
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"MyCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.textLabel.text = #"Filler text";
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 0;
}
- (void)presentingDatesFrom:(NSDate *)fromDate to:(NSDate *)toDate delegate:(id<KalDataSourceCallbacks>)delegate{
NSLog(#"getting data");
if ([events count] > 0) {
[delegate loadedDataSource:self];
return;
}
NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
[fmt setDateFormat:#"yyyy-MM-dd hh:mm:ss"];
PFUser *user = [PFUser currentUser];
PFQuery *query = [PFQuery queryWithClassName:#"CalendarEvents"];
[query whereKey:#"user" equalTo:user];
[query findObjectsInBackgroundWithBlock:^(NSArray *objects, NSError *error) {
if (!error) {
[events removeAllObjects];
[events addObjectsFromArray:objects];
[delegate loadedDataSource:self];
} else {
NSLog(#"Error: %# %#", error, [error userInfo]);
}
}];
}
- (NSArray *)markedDatesFrom:(NSDate *)fromDate to:(NSDate *)toDate {
return [[self tagsFrom:fromDate to:toDate] valueForKeyPath:#"date"];
}
- (void)loadItemsFromDate:(NSDate *)fromDate toDate:(NSDate *)toDate {
[items addObjectsFromArray:[self tagsFrom:fromDate to:toDate]];
}
- (NSArray *)tagsFrom:(NSDate *)fromDate to:(NSDate *)toDate
{
NSMutableArray *matches = [NSMutableArray array];
for (PFObject *event in events){
if (IsDateBetweenInclusive([event objectForKey:#"event_date"], fromDate, toDate)){
[matches addObject:event];
}
}
return matches;
}
- (void)removeAllItems{
[items removeAllObjects];
}
#end
My view controller holding the calendar.
#import "MainMenuViewController.h"
#import "Kal.h"
#import "KalParseDataSource.h"
#interface MainMenuViewController ()
#end
#implementation MainMenuViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
id<KalDataSource> source = [[KalParseDataSource alloc] init];
KalViewController *calendar = [[KalViewController alloc] init];
calendar.dataSource = source;
[self addChildViewController:calendar];
[calendar didMoveToParentViewController:self];
[self.view addSubview:calendar.view];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
I'm stuck with this for 3 days, Can anyone give simple example in using this 3rd party framework https://github.com/klazuka/Kal ? The one on the repo seems a bit complicated, I just want to use a custom data source.
it seems that the function cc_componentsForMonthDayAndYear you are calling with null just put a debug there from wherever the function is being called and check if the function being called is on NSDate and it is not released.
And you can always Enable Zombies to find the released object when crash happens. You can track if any variable gets released via setting NSZombieEnabled to YES. With zombies enabled, messages to deallocated objects will no longer behave strangely or crash in difficult-to-understand ways, but will instead log a message and die in a predictable and debugger-breakpointable way.
You can set NSZombieEnabled by the following steps.
Select Product from the menu bar above. Keep alt/option pressed and select "Test..." or "Run...".
1.
Go to the Arguments tab, and add NSZombieEnabled YES in the "Environment Variables" section.
OR
2.
Go to the Diagnostics tab, and check Enable Zombie Objects in the "Memory Management" section.

NSZombieEnabled prevents my app from crashing

So I've been debugging like a mad men using NSZombiesEnabled and NSZombies in Instruments. However when running the app using zombies it seems to resolve my issue. When I run the app without NSZombiesEnabled or NSZombies in instruments it crashes. Any idea on how to deal with this?
So the issue is that I am releasing something twice, but can't seem to find where I am doing this. Turning on NSZombieEnabled won't help as the program runs fine without telling me where I am over releasing.
So I think I kind of know where it's crashing, I have this globalArray Singleton class that I am creating:
extern NSString * const kClearDataSource;
#interface AHImageDataSource : NSObject
+ (AHImageDataSource *)sharedDataSource;
- (void) clearDataSource;
- (void) addObject:(id) object;
- (void) addObject:(id)object atIndex:(int) index;
- (int) count;
- (id) objectAtIndex:(int) index;
#end
NSString * const kClearDataSource = #"clearDataSource";
#interface AHImageDataSource()
{
NSMutableArray * imageDataSource_;
}
#property (nonatomic, retain) NSMutableArray * imageDataSource_;
#end
#implementation AHImageDataSource
#synthesize imageDataSource_;
+ (AHImageDataSource *)sharedDataSource {
static AHImageDataSource *_sharedClient = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedClient = [[self alloc] init];
});
return _sharedClient;
}
- (id)init {
self = [super init];
if (!self) {
return nil;
}
NSMutableArray * temp = [[NSMutableArray alloc] initWithCapacity:200];
self.imageDataSource_ = temp;
[temp release];
return self;
}
-(void) clearDataSource
{
if ([self.imageDataSource_ count] > 0){
[self.imageDataSource_ removeAllObjects];
}
}
- (void) addObject:(id) object
{
[self.imageDataSource_ addObject:object];
}
- (void) addObject:(id)object atIndex:(int) index
{
[self.imageDataSource_ insertObject:object atIndex:index];
}
- (int) count
{
return [self.imageDataSource_ count];
}
- (id) objectAtIndex:(int) index
{
if (index >= 0 && index < [self.imageDataSource_ count]){
return [self.imageDataSource_ objectAtIndex:index];
}
return nil;
}
- (void) dealloc
{
[super dealloc];
[imageDataSource_ release];
}
#end
at one point of the code I am trying to remove all of the objects in the array and then adding some stuff in. When that happen the crashed happened.
This part of the code crashes the second time it was executed:
NSArray *arr = [response valueForKey:#"data"];
if ([arr count] > 0){
[[AHImageDataSource sharedDataSource] clearDataSource];
}
for (NSDictionary * data in arr){
AHInstagramImageData * imgData = [[AHInstagramImageData alloc] initWithData:data];
[[AHImageDataSource sharedDataSource] addObject:imgData];
[imgData release];
}
You should definitely not do [super dealloc] first in your -dealloc method. It must come last.
Go go Product -> Analyze. The messages displayed will give you the solution or an idea.
Your app crashes when an object that has been deallocated is sent a message. NSZombiesEnabled prevents your app from crashing because it holds on to all deallocated objects (and thus leaks everything). It will print a message in the console when a deallocated object is sent a message (which would normally crash your app). Something to the affect of "message 'bar' sent to deallocated object 'foo'" (or something like that). It does not actually pause execution of your app.
When you've passed the point where you know your app generally crashes, check the console log for a message similar to the one above.

Why is only one attribute of my <NSCoding> object being properly written to a file?

So I'm trying to write a NSMutableArray of custom objects (a "Course" representing a college course for a Course Planner app) to a file when my application terminates and then read that array from the file into the relevant ViewController that will make use of the data when the application starts up.
Here is the relevant code:
CoursesAppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
coursesViewController = [[SampleHomeScreen alloc] initWithNibName:#"SampleHomeScreen" bundle:nil];
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[coursesViewController setCourses:[NSKeyedUnarchiver unarchiveObjectWithFile: filePath]];
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(applicationWillTerminate:)name:UIApplicationWillTerminateNotification object:app];
[window addSubview:coursesViewController.view];
[window makeKeyAndVisible];
return YES;
}
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:#"data.plist"];
NSLog(#"%#", path);
return path;
}
/**
applicationWillTerminate: saves changes in the application's managed object context before the application terminates.
*/
- (void)applicationWillTerminate:(UIApplication *)application {
NSLog(#"%#", [coursesViewController courses]);
[NSKeyedArchiver archiveRootObject:[coursesViewController courses] toFile:[self dataFilePath]];
}
Course.h:
#interface Course : NSObject <NSCoding> {
NSString *name; //e.g. ECS 189H
double grade, totalWeight; //course grade in %
NSMutableArray *list;
}
#property (nonatomic, retain) NSString *name;
#property (nonatomic) double grade, totalWeight;
#property (nonatomic, retain) NSMutableArray *list;
-(Course *)initWithName:(NSString *)courseName;
#end
Course.m:
#implementation Course
#synthesize name, grade, totalWeight, list;
-(Course *)initWithName:(NSString *)courseName {
name = [courseName retain];
grade = -1.0;
totalWeight = 0.0;
list = [[NSMutableArray alloc] init];
[super init];
return self;
}
-(Course *)initWithCoder:(NSCoder *)aDecoder {
self.name = [aDecoder decodeObjectForKey:#"name"];
self.grade = [aDecoder decodeDoubleForKey:#"grade"];
self.totalWeight = [aDecoder decodeDoubleForKey:#"totalWeight"];
self.list = [aDecoder decodeObjectForKey:#"list"];
[super init];
return self;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
[coder encodeObject:name forKey:#"name"];
[coder encodeDouble:grade forKey:#"grade"];
[coder encodeDouble:totalWeight forKey:#"totalWeight"];
[coder encodeObject:list forKey:#"list"];
}
-(void)dealloc {
[name release];
[list release];
[super dealloc];
}
#end
[coursesViewController courses] is the NSMutableArray that holds the course objects. I know for a fact that it holds valid data.
So the problems are,
1: The application saves to data.plist ONLY when I run it from xcode (ie click "compile and run" in xcode).
2: It loads data from the plist, but all that gets saved are the course names and the default values for grade and totalWeight (-1 and 0 respectively). So really they are saved as though initWithName was called on them first.
This is my first real delve into a fairly advanced iOS application, so as I am a newbie to this, I may have left out some important info. If that is the case, please let me know and I will update the question.
Thanks!
-HT
p.s. If it is relevant, I have doNotRunInBackground in the info.plist set to true.
Your are trying to set values in your object before it's been initialized. And initialization will then reset your values.
-(Course *)initWithName:(NSString *)courseName {
name = [courseName retain]; // <- Accessing ivar before self is initialized
grade = -1.0; // <- Accessing ivar before self is initialized
totalWeight = 0.0; // <- Accessing ivar before self is initialized
list = [[NSMutableArray alloc] init]; // <- Accessing ivar before self is initialized
[super init]; // initialization resets your values !!!!
return self;
}
Additionally you are ignoring super's init return value, which will work fine 98 % of all cases, but I recommend to always use a proper initialization scheme:
- (id)init {
if (self = [super init]) {
// It's save to access ivars here
}
return self
}
In Cocoa an init method may return a different object, then the one that was allocated. So you must assign self to the super's init.
So, your init should look like:
-(Course *)initWithName:(NSString *)courseName {
if (self = [super init]) {
name = [courseName retain];
grade = -1.0;
totalWeight = 0.0;
list = [[NSMutableArray alloc] init];
}
return self;
}
The same applies to initWithCoder:(NSCoder *)coder.

NSMutableArray for Object which has NSString property causes memory leak

I hope to add objects to a NSMutableArray "myArray", The NSMutableArray is the array for FileObj which has a NSString property "fileName"
#import <UIKit/UIKit.h>
#interface FileObj : NSObject {
NSString *fileName;
}
-(void) setfileName:(NSString *)s ;
-(NSString *) getfileName ;
#end
//
// File.m//
#import "File.h"
#implementation FileObj
-(void) setfileName:(NSString *)s ;
{
fileName=s;
}
-(NSString *) getfileName ;
{
return fileName;
}
#end
I initialize the myArray here:
NSMutableArray *temarray;
temarray=[[NSMutableArray alloc] init];
self.myArray=temarray;
[temarray release];
the codes to add object to myArray
FileObj *newobj=[[FileObj alloc]init ];
NSString *fieldValue2 = [[NSString alloc] initWithUTF8String:#"aaaa"];
[newobj setfileName:fieldValue2];
[myArray addObject:newobj];
[fieldValue2 release]; //**if I enabled the line, it will cause crash**
//**if I disable the line, it will cause memory leak**
[newobj release];
Welcome any comment
Thanks
interdev
First you should look into ObjC naming conventions. There is no -get methods in ObjC. It's also a good idea to prefix your classes with your own 2 letters (like NS).
Your setter value assignment is invalid and the NSString initialization unnecessary.
I would strongly recommend introductory material to you!
#interface MYFileObject : NSObject {
NSString *_fileName;
}
- (void)setFileName:(NSString *)theString;
- (NSString *)fileName;
#end
and the implementation
#implementation MYFileObject
- (void)setFileName:(NSString *)theString {
[_fileName release];
_fileName = [theString copy];
}
- (NSString *)fileName {
return [[_fileName copy] autorelease];
}
- (void)dealloc {
[_fileName release];
[super dealloc];
}
#end
You would add an object like this...
NSMutableArray *myAry = [[NSMutableArray alloc] init];
MYFileObject *obj = [[MYFileObject alloc] init];
[obj setFileName:#"thefilename.txt"];
[myAry addObject:obj];
[obj release];
I would recommend using properties instead of defining your own getters/setters.
You could also use the NSMutableArrays' designated initializers for fast array creation.
Look here for how to use properties: http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html
Why bother with getters and setters? Use declared property already!
#interface FileObj : NSObject {
NSString *fileName;
}
#property(retain,nonatomic) NSString* fileName; // <---
#end
...
#implementation FileObj
#synthesize fileName; /// <---
-(void)dealloc {
[fileName release]; // Remember to release the object on dealloc.
[super dealloc];
}
#end
...
FileObj *newobj=[[FileObj alloc] init];
NSString *fieldValue2 = [[NSString alloc] initWithUTF8String:#"aaaa"];
newobj.fileName = fieldValue2; /// <----
[myArray addObject:newobj];
[fieldValue2 release];
[newobj release];
The crash occurs because the NSString instance is not retained anymore.
A common pattern is to retain NSString properties, either declaratively with #property or by hand.
You should modify the setter like this:
-(void) setfileName:(NSString *)s ;
{
[s retain]; // <- Retain new value
[filename release]; // <- Release old value
fileName=s;
}

Singleton Class iPhone

Ok, I'm trying to avoid global variables, so I read up on singleton classes.
This is a try to set and read a mutable array, but the result is null.
//Content.h
#interface Content : NSObject {
NSMutableArray *contentArray;
}
+ (Content *) sharedInstance;
- (NSMutableArray *) getArray;
- (void) addArray:(NSMutableArray *)mutableArray;
#end
.
//Content.m
#implementation Content
static Content *_sharedInstance;
+ (Content *) sharedInstance
{
if (!_sharedInstance)
{
_sharedInstance = [[Content alloc] init];
}
return _sharedInstance;
}
- (NSMutableArray *) getArray{
return contentArray;
}
- (void) addArray:(NSMutableArray *)mutableArray{
[contentArray addObject:mutableArray];
}
#end
And in a ViewController I added #import "Content.h", where I try to call this:
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:#"test",#"foo",#"bar",nil];
Content *content = [Content sharedInstance];
[content addArray:mArray];
NSLog(#"contentArray: %#", [content getArray]);
You need to alloc and init the array first. Personally I'd do it in the init method of the content class like so:
-(id)init{
if(self = [super init]){
…the rest of your init code…
contentArray = [[NSMutableArray alloc] init];
}
return self;
}
You never actually alloc/initialise the contentArray array.