Newbie question: NSOperation for iphone SDK - iphone

Hi I got some problem with NSOperation .
I always got error at self = [super init]; (already use break point to find this)
it always return "Program received signal: EXC_BAD_ACCESS" all the time
//AddThread.h
#interface AddThread : NSOperation
{
NSString * str;
}
#property (nonatomic,retain) NSString * str;
-(id) initWithString:(NSString *) tmpStr;
#end
and for .m
//AddThread.m
#import "AddThread.h"
#implementation AddThread
#synthesize str;
- (id) initWithString:(NSString *)tmpStr
{
self = [super init];
if (self != nil)
{
self.str = tmpStr;
}
//NSLog(self);
//[super init];
return self;
}
- (void) main
{
NSLog(self.str);
}
- (void) dealloc{
[str release];
str = nil;
[super dealloc];
}
#end
well I stuck with this for while and if possible any resources ,articles things for basic example of NSoperation?

In your main method, you are calling NSLog(self.str) - While this will work if the object you pass in is a string, it won't work if you continue to try and log other objects. NSLog takes a format string as a parameter. If you just do NSLog(self) like you are in some of your commented code, and self is not a string, it'll crash because it expected a string. You should do NSLog(#"self: %#", self) the %# will print out the string returned by an objects description method.
Other than that, your init method looks fine, how exactly are you creating an instance of this object? Could you show the code for that? The problem may lie there.

Related

How to use Protocols objective-c

I need to inherit Picker selected values into the other place .I am trying the below code but null value is coming ..please check where I am going wrong.
I have to Inherit String values that is been passes in the PickerView..please check the code
Picker1.h
#import <UIKit/UIKit.h>
#protocol pickerDelegate <NSObject>
-(void)didFinishPicking:(NSString *)pickedStr;
#end
#interface
#property(nonatomic,retain)id<pickerDelegate>delegate;
picker.m
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
string=[NSString stringWithFormat:#"%#",[list objectAtIndex:row]];
label.text=string;
[self.delegate didFinishPicking:string];
}
- (void)viewDidLoad
{
[super viewDidLoad];
list =[[NSMutableArray alloc]init];
[list addObject:#"a"];
[list addObject:#"b"];
}
Acitivity_1.h
#import <UIKit/UIKit.h>
#import "Picker1.h"
#interface Activity_1 : UIViewController<UIApplicationDelegate, pickerDelegate>{
#property(nonatomic,retain)Picker1 *delegate1;
#property (nonatomic,retain)NSString *str;
#end
Activity_1.m
- (void)viewDidLoad
{
[super viewDidLoad];
**this is how i print the value but value is null**
NSLog(#"delegate1%#",self.delegate1.string);
delegate1 = [[Picker1 alloc] init];
[delegate1 setDelegate : self];
}
-(void)didFinishPicking:(NSString *)pickedStr
{
[self setStr:pickedStr];
}
You are printing out a value of a delegate just before you are setting it up....so it will print null. You should print out your string when the didFinishPicking method is called instead since this is where you are setting up your string.
-(void)didFinishPicking:(NSString *)pickedStr
{
[self setStr:pickedStr];
// print the string you have just picked here if you want
NSLog(#"Picked string: %#",pickedStr);
}
Note one the side: avoid any name convention with number such as Activity_1, Picker1 this is extremely bad code practice.
You are NSLogging delegate before creating self.delegate1 itself
Please use the below lines of code.
delegate1 = [[Picker1 alloc] init];
[delegate1 setDelegate : self];
And put NSLog inside "didFinishPicking"
-(void)didFinishPicking:(NSString *)pickedStr
{
NSLog(#"pickedStr%#", pickedStr);
[self setStr:pickedStr];
}

Correct way to create/use a Singleton NSMutableArray for Xcode 4

I've reviewed (and tried) a bunch of the threads here regarding Singletons and NSMutableArrays. I'm new to Objective-C so please bear with me.
I simply want to create a few arrays that can be accessed from any view/.m file.
What is the best (or most concise) coding for a Singleton?
Below is what I have now and I get
1 warning at .m '#implementation' - "Incomplete implementation"
1 error at usage in a view .m file - "initializer element is not a compile-time constant"
This is the code I have now - my GlobalData.h file:
#import <Foundation/Foundation.h>
#interface GlobalData : NSObject {
NSMutableArray *listOfHeadings;
NSMutableArray *listOfItems1;
NSMutableArray *listOfItems2;
}
#property(nonatomic,retain)NSMutableArray *listOfHeadings;
#property(nonatomic,retain)NSMutableArray *listOfItems1;
#property(nonatomic,retain)NSMutableArray *listOfItems2;
+(GlobalData*)getInstance;
#end
My GlobalData.m file:
#import "GlobalData.h"
#implementation GlobalData
#synthesize listOfHeadings;
#synthesize listOfItems1;
#synthesize listOfItems2;
static GlobalData *instance=nil;
+(GlobalData *)getInstance
{
#synchronized(self)
{
if(instance==nil)
{
instance= [GlobalData new];
}
}
return instance;
}
#end
And in a view .m file (simplified):
#import GlobalData.h
GlobalData *globDat=[GlobalData getInstance]; //error occurs here
Can someone point out the trouble and if there's better coding, please enlighten me - thanks!
EDIT
Here's a few links I've tried to use:
Can i have a single NSMutableArray in my multiple views application?
iPhone help with singleton class
In this case, you might be doing more than you have to. Granted this certainly isn't always the best solution - but you can put your NSMutableArray as a property in your App Delegate and then easily refer to it from any view. By doing it this way - you aren't locking it in as a 'singleton' but there is a 'singleton instance' of it (this helps a great deal for testability).
I have simplified this process here:
YourAppDelegate.h
#property (nonatomic,retain) NSMutableArray *myArray;
YourAppDelegate.m
#synthesize myArray;
YourViewController.m
YourAppDelegate *appDelegate = (YourAppDelegate *)[[UIApplication sharedApplication] delegate];
NSMutableArray *myArrayFromAppDelegate = appDelegate.myArray;
From this point - you can do any manipulation on this value.
Here's the "modern" version of a single method to turn any class into a Singleton (in this case formatted as a code snippet). It works in iOS4.x or higher:
+(<#SingletonClassName#> *) sharedInstance
{
static <#SingletonClassName#> *_sharedClient = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedClient = [[self alloc] init];
});
return _sharedClient;
}
But, do you really need a singleton of a single NSMutableArray? You could use the built-on singleton - your application delegate, which is got to by calling:
MyAppDelegate * appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate.myMutableArray addObject:...];
The error initializer element is not a compile-time constant is not related to how you create your singleton. The error is how you are accessing your singleton. You are doing this outside of a function:
GlobalData *globDat=[GlobalData getInstance];
This means that you are trying to initialize a global variable (globDat) as the value of the expression [GlobalData getInstance]. You can only initialize global variables to expressions that are "compile-time constants". That means things like 0 or "fred" or 8/2. The value of [GlobalData getInstance] cannot be computed at compile-time, so it cannot be used to initialize the global variable.
Instead, you need to just use [GlobalData getInstance] inside your function bodies wherever you are currently trying to use the globDat variable.
As for the warning, Incomplete implementation, I don't see what's missing. Perhaps you didn't post all of the code from GlobalData.h. Anyway, you should be able to click the warning (where it appears on the right side of the editor window) and have Xcode show you what's missing.
This is the way I create my Singleton:
Singleton.h
#import <Foundation/Foundation.h>
#interface Singleton : NSObject {
NSMutableArray *firstMutableArray;
NSMutableArray *secondMutableArray;
}
#property (nonatomic, retain) NSMutableArray *firstMutableArray;
#property (nonatomic, retain) NSMutableArray *secondMutableArray;
+ (id)sharedSingleton;
#end
Sigleton.m
#import "Singleton.h"
static Singleton *sharedMySingleton = nil;
#implementation Singleton
#synthesize firstMutableArray;
#synthesize secondMutableArray;
#pragma mark Singleton Methods
+ (id)sharedSingleton {
#synchronized(self) {
if (sharedMySingleton == nil) {
sharedMySingleton = [[super allocWithZone:NULL] init];
}
return sharedMySingleton;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedSingleton] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (unsigned)retainCount {
return UINT_MAX;
}
- (oneway void)release {
// Never release
}
- (id)autorelease {
return self;
}
- (id)init {
if (self = [super init]) {
firstMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
secondMutableArray = [[NSMutableArray alloc] initWithObjects:nil];
}
return self;
}
- (void)dealloc {
[firstMutableArray release];
[secondMutableArray release];
[super dealloc];
}
#end
Then, when you want to call your Singleton:
#import "Singleton.h"
Singleton *singleton = [Singleton sharedSingleton];
singleton.firstMutableArray = ...
singleton.secondMutableArray = ...

endless loop adding a subview

I am a little confused, and after countless attempts and read several articles I decided to write.
my problem is that if you call a method from a class (xml) and it is aimed at viewcontroller all goes well
but if I might add [self.view add...] it back to the top reloading the viewDidLoad of the viewController class entering into an endless loop.
this is what I do
class (ViewController)
.h
#import <UIKit/UIKit.h>
#class XMLStuff;
#interface skiSpeedViewController : UIViewController {
}
#property (nonatomic, retain) XMLStuff *xml;
.m
- (void)viewDidLoad
{
[super viewDidLoad];
xml.skiSpeedC = self;
GpsStuff *gps = [GpsStuff alloc];
[gps init];
}
gps.m
- (id)init
{
self = [super init];
if (self) {
xml = [XMLStuff alloc];
}
}
-(void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
[xml lon:newLocation.coordinate.longitude lat:newLocation.coordinate.latitude];
xml.h
#import "skiSpeedViewController.h"
#class skiSpeedViewController;
#interface XMLStuff : NSObject <NSXMLParserDelegate> {
}
#property (retain, nonatomic) skiSpeedViewController *skiSpeedC;
.m
#synthesize skiSpeedC;
- (void) parserDidEndDocument:(NSXMLParser *)parser {
NSLog(#"--%#", self.skiSpeedC); // Return (null)
[self.skiSpeedC riceviDic:datiMeteo];
}
ViewController.m
-(void)riceviDic:(NSMutableDictionary *)dictMeteo {
datiMeteo = [[NSMutableDictionary alloc]initWithDictionary:dictMeteo];
}
}
- (void) parserDidEndDocument:(NSXMLParser *)parser {
classViewController *skiSpeedC = [classViewController alloc];
[skiSpeedC riceviDic:datiMeteo];
}
You are creating a new instance of classViewController every time. Your "xml" class (XMLStuff?) should have a pointer to the view controller and be calling the riceviDic method on that instance.
You're getting an infinite loop because when you allocate the XML object in viewDidLoad, it too starts parsing the XML, then creates more XML objects, which then create more viewControllers...
So, add a property to XMLStuff of type classViewController, and when you create it in viewDidLoad:
xml.skiSpeedC = self;
Then, in parserDidEndDocument:
- (void) parserDidEndDocument:(NSXMLParser *)parser {
[self.skiSpeedC riceviDic:datiMeteo];
}
UPDATE
OK, after your edit things look very different - you seem to have introduced a new class - GpsStuff, which has its own instance of XMLStuff (and a dodgy looking init method which I assume you haven't copied in properly?). Which one is actually parsing your document? XMLStuff in your view controller, or in GPSStufF? I'm guessing the one in GPSStuff, which you haven't set the skiSpeedC property for. I was previously assuming that you were calling everything from your view controller.
Why not remove the creation of a new XMLStuff object from GPSStuff, and when you create GPSStuff in your view controller, pass the xml object you've created into it:
- (void)viewDidLoad
{
[super viewDidLoad];
GpsStuff *gps = [[GpsStuff alloc] init];
XMLStuff *xml = [[XMLStuff alloc] init];
xml.skiSpeedC = self;
gps.xml = xml;
[xml release];
}
Also, the skiSpeedC property should probably not be retain, since it is essentially a delegate assignment and the view controller is not going to be released before you release the xml parser.
As a note, by convention you should be initializing objects like this:
GPSStuff *gps = [[GPSStuff alloc] init];
Not on two lines. You want what is returned from init to be assigned to your variable.

Data going missing when passed between threads using a Singleton

Edit:
Thanks #BlackFrog. I think I'm nearer now, but the values are still not get getting through...
The values are set as shown by logs within [progressController updateProgressSummary:...] but are nil when I log them in progressUpdate initWithProgressUpdate:.... as shown below.
I'm slightly confused over which property is used the one set for progressUpdate or the ones set for each of the 3 components of progressUpdate. I have changed the 3 individual properties from assign to retain as suggested and have also tried doing the same with the overall progressUpdate property too (not shown here).
progressController.h
......
#property (nonatomic, assign) ProgressUpdate *progressUpdate;
progressController.m
// Ask delegate to update and display Progress text
-(void) updateProgressSummary:(NSString *)summary detail:(NSString *)detail percentComplete:(NSNumber *)complete {
// These report the proper values
DLog(#"Reporting Summary - %s", [summary UTF8String]);
DLog(#"Reporting Detail - %s", [detail UTF8String]);
DLog(#"Reporting Complete - %i", [complete intValue]);
if (summary != nil)
self.progressUpdate.summaryText = summary;
self.progressUpdate.detailText = detail;
self.progressUpdate.percentComplete = complete;
ProgressUpdate *progressUpdateForIssue = [[ProgressUpdate alloc] initWithProgressUpdate:progressUpdate];
[self.delegate performSelectorOnMainThread:#selector(displayProgress:) withObject:progressUpdateForIssue waitUntilDone:NO];
[progressUpdateForIssue release];
}
But then a few milliseconds later...., inside the object....they're nil.
progressUpdate.h
.....
#property (nonatomic, retain) NSString *summaryText;
#property (nonatomic, retain) NSString *detailText;
#property (nonatomic, retain) NSNumber *percentComplete;
progressUpdate.m
-(id) initWithProgressUpdate:(ProgressUpdate *)update {
if ((self = [super init])) {
summaryText = [update.summaryText copy];
detailText = [update.detailText copy];
percentComplete = [[NSNumber alloc] initWithFloat:[update.percentComplete floatValue]];
}
// These report nil values
DLog(#"Reporting in progUpdate summaryText - %s", [summaryText UTF8String]);
DLog(#"Reporting in progUpdate detailText - %s", [detailText UTF8String]);
DLog(#"Reporting in progUpdate percentComplete - %i", [percentComplete intValue]);
return self;
}
end of update
I need some help with passing data in a custom class from one thread to another. Its there before the pass but then disappears upon arrival. I've tried everything I know, but to no avail.
My background thread calls ProgressController and passes it details of the current progress. That in turn does performSelectorOnMainThread on ProgressController's delegate (the view controller) to display the details.
It was all working fine when I was passing through a single NSString, but I need to pass two strings and a number and as performSelectorOnMainThread can only pass one object, I have encapsulated these in a custom object - ProgressUpdate.
The data gets through to ProgressController correctly but is null by the time that it appears in the View Controller. I know this as I've put NSLogs in various places.
I wonder if its to do with:
multithreading and custom objects
the fact that ProgressController is a singleton, which is why I have then alloc'd a new ProgressUpdate each time its called, but that has not helped.
Any ideas welcome. For clarity, the code is below.
ProgressUpdate.h
#import <Foundation/Foundation.h>
#interface ProgressUpdate : NSObject {
NSString *summaryText;
NSString *detailText;
NSNumber *percentComplete;
}
#property (nonatomic, assign) NSString *summaryText;
#property (nonatomic, assign) NSString *detailText;
#property (nonatomic, assign) NSNumber *percentComplete;
-(id) initWith:(ProgressUpdate *)update;
#end
ProgressUpdate.m
#import "ProgressUpdate.h"
#implementation ProgressUpdate
#synthesize summaryText, detailText, percentComplete;
-(id) initWith:(ProgressUpdate *)update {
self = [super init];
self.summaryText = update.summaryText;
self.detailText = update.detailText;
self.percentComplete = update.percentComplete;
return self;
}
#end
ProgressController.m
static ProgressController *sharedInstance;
+ (ProgressController *)sharedInstance {
#synchronized(self) {
if (!sharedInstance)
[[ProgressController alloc] init];
}
return sharedInstance;
}
+(id)alloc {
#synchronized(self) {
NSAssert(sharedInstance == nil, NSLocalizedString(#"Attempted to allocate a second instance of a singleton ProgressController.", #"Attempted to allocate a second instance of a singleton ProgressController."));
sharedInstance = [super alloc];
}
return sharedInstance;
}
-(id) init {
if (self = [super init]) {
[self open];
}
return self;
}
.........
// Ask delegate to update and display Progress text
-(void) updateProgressSummary:(NSString *)summary detail:(NSString *)detail percentComplete:(NSNumber *)complete {
if (summary != nil)
self.progressUpdate.summaryText = summary;
self.progressUpdate.detailText = detail;
self.progressUpdate.percentComplete = complete;
ProgressUpdate *progressUpdateForIssue = [[ProgressUpdate alloc] initWith:progressUpdate];
[self.delegate performSelectorOnMainThread:#selector(displayProgress:) withObject:progressUpdateForIssue waitUntilDone:NO];
[progressUpdateForIssue release];
}
RootViewController.m
// Delegate method to display specific text in Progress label
- (void) displayProgress:(ProgressUpdate *)update {
[progressSummaryLabel setText:update.summaryText];
[progressDetailLabel setText:update.detailText];
[progressBar setProgress:[update.percentComplete intValue]];
[progressView setNeedsDisplay];
}
In the init method, you are only assigning the ivars and not retaining them in the new object.
Redo your init method as the following:
-(id) initWithProgressUpdate:(ProgressUpdate *)update {
if ((self = [super init])) {
summaryText = [update.summaryText copy];
detailText = [update.detailText copy];
percentComplete = [[NSNumber alloc] initWithFloat:[update.percentComplete floatValue];
}
return self;
}
Couple of points:
You should not use accessor in the init method
Rename your init method to be a lot clear
In the #property, change the assign to retain
Try removing the statement '[progressUpdateForIssue release];' in the method
'-(void) updateProgressSummary:(NSString *)summary detail:(NSString *)detail percentComplete:(NSNumber *)complete '.
Also change the property attribute from 'assign' to 'retain' in your class ProgressUpdate.
You could release those properties in the dealloc method .
Good luck.

Subclass NSCache - App Singleton

I am writing an iPhone app and I want to create a NSCache singleton.
I am having trouble, here's the code that I have:
MyAppCache.h:
#import <Foundation/Foundation.h>
#interface MyAppCache : NSCache {}
+ (MyAppCache *) sharedCache;
#end
MyAppCache.m:
#import "SpotmoCache.h"
static MyAppCache *sharedMyAppCache = nil;
#implementation MyAppCache
+ (MyAppCache *) sharedCache {
if (sharedMyAppCache == nil) {
sharedMyAppCache = [[super allocWithZone:NULL] init];
}
return sharedMyAppCache;
}
+ (id)allocWithZone:(NSZone *)zone {
return [[self sharedCache] retain];
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
- (id)retain {
return self;
}
- (NSUInteger)retainCount {
return NSUIntegerMax; //denotes an object that cannot be released
}
- (void)release{
//do nothing
}
- (id)autorelease {
return self;
}
#end
When I want to add something or get something from the cache I might write:
#import "MyAppCache.h"
MyAppCache *theCache = [MyAppCache sharedCache];
Then:
NSData *someData = [[theCache objectForKey: keyString] retain];
Or:
[theCache setObject: someData forKey: keyString cost: sizeof(someData)];
The problem: the compiler complains 'MyAppCache' may not respond to 'method' for each of those lines.
I might be doing something completely wrong here - know how to make this work?
If the first listing is MyAppCache.h, then you're sticking #implementation in a header file, which isn't likely to do the right thing (the linker will probably complain).
If the first listing is MyAppCache.m, then you need to move the #interface into MyAppCache.h.
Also note that your code suffers from double-initing: [[MyAppCache alloc] init] is effectively [[[MyAppCache sharedCache] retain] init]. I don't know what NSCache does when inited twice, but it probably isn't good. I really wouldn't bother implementing copyWithZone: (I'm pretty sure objects aren't copyable by default), and you can just override allocWithZone: to raise an exception.
(And +sharedCache isn't thread-safe, which may or may not be an issue.)
OK, got it. I had a copy (previous version) of the MyAppCache.h and MyAppCache.m files still sitting in a folder in the project!