polymorphism and inheritance in objective-c example - ios

I'm trying to understand polymorphism and inheritance. I don't have too much experience in it. What I'm basically trying to do is have a generic BaseFileLogic class that can open a file from the bundle. I have subclasses of the BaseFileLogic class that have the file name as a constant for those specific subclasses. The idea was basically for someone who dragged a file name I specify from iTunes sharing, I could open the file and parse it for my different object types. So my BaseFileLogic class is pretty simple with a class and designated initializer:
- (id)initWithFileName:(NSString *)fileName fileLocation:(FileLocation)fileLocation {
if (self = [super init]) {
_currentFile = fileName;
NSString *filePath = nil;
if (fileLocation == FileLocationBundle) {
filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:#"csv"];
}
else {
filePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:_currentFile];
}
_parser = [[CHCSVParser alloc] initWithContentsOfCSVFile:filePath];
_parser.delegate = self;
}
return self;
}
+ (id)baseFileLogicWithFileName:(NSString *)fileName fileLocation:(FileLocation)fileLocation {
return [[CRBaseFileLogic alloc] initWithFileName:fileName fileLocation:fileLocation ];
}
Now in my RoastLogic class, I have this so far:
#interface CRRoastFileLogic : CRBaseFileLogic
+ (id)roastFileLogicFromFileLocation:(FileLocation)fileLocation;
#end
#implementation CRRoastFileLogic
+ (id)roastFileLogicFromFileLocation:(FileLocation)fileLocation {
CRBaseFileLogic *cr = [CRBaseFileLogic baseFileLogicWithFileName:(NSString *)kRoastFileName fileLocation:fileLocation];
NSLog(#"cr: %#", [cr description]);
return cr;
}
#end
When I print out the description, the cr object is of type CRBaseFileLogic. I guess at this part I'm confused because I want to create an instance of CRRoastFileLogic, but use methods that I have declared in the superclass. How is inheritance /polymorphism supposed to work?

in this method
+ (id)baseFileLogicWithFileName:(NSString *)fileName fileLocation:(FileLocation)fileLocation {
return [[CRBaseFileLogic alloc] initWithFileName:fileName fileLocation:fileLocation ];
}
you have the problem. Because it always return an instance of CRBaseFileLogic
so change it like this should solve the problem
+ (id)baseFileLogicWithFileName:(NSString *)fileName fileLocation:(FileLocation)fileLocation {
return [[self alloc] initWithFileName:fileName fileLocation:fileLocation ];
}
then the self will be CRRoastFileLogic if you call it like [CRRoastFileLogic baseFileLogicWithFileName...]

Related

Transform (or copy) an object to a subclass instance in Objective-C

I want to transform an instance of an object into an instance of a subclass of that object class, so that I can use the additional methods and properties of that subclass, in Objective-C.
How can I do this in a way that does not require me to hardcode the properties of that object class in a copy method?
It is not possible to transform an object into an instance of a subclass in Objective-C. However, with the class below you can supply an instance of both the object and the subclass and have the values of all properties copied to the subclass instance. This implementation works with both Objective-C object types and C primitives. You do not have to specify (or indeed even determine) the properties that need to be copied, providing you know that the important variables are visible and can be set (i.e., there are no properties that are exposed as "read only" or not exposed at all, whose values cannot be recalculated by the class). This method is thus relatively robust for known classes and will not require updating to support future changes you make in your object class that fit these parameters. It is iOS 8 compatible.
This class provides four class methods:
+ (id) copyObject:(id)object toSubclassObject:(id)subclassObject
Copies all properties of object to subclassObject. If the subclassObject is not a subclass of object, nil is returned.
+ (NSDictionary *) propertiesOfObject:(id)object;
Returns a dictionary of all visible properties of an object, including those from all its superclasses (other than NSObject).
+ (NSDictionary *) propertiesOfClass:(Class)class;
Returns a dictionary of all visible properties of a class, including those from all its superclasses (other than NSObject).
+ (NSDictionary *) propertiesOfSubclass:(Class)class;
Returns a dictionary of all visible properties that are specific to a subclass. Properties for its superclasses are not included.
Header:
// SYNUtilities.h
#import <Foundation/Foundation.h>
#interface SYNUtilities : NSObject
+ (id) copyObject:(id)object toSubclassObject:(id)subclassObject;
+ (NSDictionary *) propertiesOfObject:(id)object;
+ (NSDictionary *) propertiesOfClass:(Class)class;
+ (NSDictionary *) propertiesOfSubclass:(Class)class;
#end
Implementation:
#import "SYNUtilities.h"
#import <objc/runtime.h>
#import <objc/message.h>
#implementation SYNUtilities
+ (id) copyObject:(id)object toSubclassObject:(id)subclassObject
{
if (![[subclassObject class] isSubclassOfClass:[object class]]) {
return nil;
}
NSDictionary * properties = [self propertiesOfObject:object];
NSLog(#"Properties of %#:\n%#", [object class], properties);
for (NSString * property in properties) {
SEL selector = NSSelectorFromString(property);
if (selector) {
id value = [object valueForKey:property];
[subclassObject setValue:value forKey:property];
}
}
return subclassObject;
}
+ (NSDictionary *) propertiesOfObject:(id)object
{
Class class = [object class];
return [self propertiesOfClass:class];
}
+ (NSDictionary *) propertiesOfClass:(Class)class
{
if (class == NULL) {
return nil;
}
NSMutableDictionary * properties = [NSMutableDictionary dictionary];
[self propertiesForHierarchyOfClass:class onDictionary:properties];
return [NSDictionary dictionaryWithDictionary:properties];
}
+ (NSDictionary *) propertiesOfSubclass:(Class)class
{
if (class == NULL) {
return nil;
}
NSMutableDictionary *properties = [NSMutableDictionary dictionary];
return [self propertiesForSubclass:class onDictionary:properties];
}
+ (NSMutableDictionary *)propertiesForHierarchyOfClass:(Class)class onDictionary:(NSMutableDictionary *)properties
{
if (class == NULL) {
return nil;
}
if (class == [NSObject class]) {
// On reaching the NSObject base class, return all properties collected.
return properties;
}
// Collect properties from the current class.
[self propertiesForSubclass:class onDictionary:properties];
// Collect properties from the superclass.
return [self propertiesForHierarchyOfClass:[class superclass] onDictionary:properties];
}
+ (NSMutableDictionary *) propertiesForSubclass:(Class)class onDictionary:(NSMutableDictionary *)properties
{
unsigned int outCount, i;
objc_property_t *objcProperties = class_copyPropertyList(class, &outCount);
for (i = 0; i < outCount; i++) {
objc_property_t property = objcProperties[i];
const char *propName = property_getName(property);
if(propName) {
const char *propType = getPropertyType(property);
NSString *propertyName = [NSString stringWithUTF8String:propName];
NSString *propertyType = [NSString stringWithUTF8String:propType];
[properties setObject:propertyType forKey:propertyName];
}
}
free(objcProperties);
return properties;
}
static const char *getPropertyType(objc_property_t property) {
const char *attributes = property_getAttributes(property);
char buffer[1 + strlen(attributes)];
strcpy(buffer, attributes);
char *state = buffer, *attribute;
while ((attribute = strsep(&state, ",")) != NULL) {
if (attribute[0] == 'T' && attribute[1] != '#') {
// A C primitive type:
/*
For example, int "i", long "l", unsigned "I", struct.
Apple docs list plenty of examples of values returned. For a list
of what will be returned for these primitives, search online for
"Objective-c" "Property Attribute Description Examples"
*/
NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
}
else if (attribute[0] == 'T' && attribute[1] == '#' && strlen(attribute) == 2) {
// An Objective C id type:
return "id";
}
else if (attribute[0] == 'T' && attribute[1] == '#') {
// Another Objective C id type:
NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
}
}
return "";
}
#end
I needed to create a subclass of NSTextFieldCell, used in an NSTableView, and wanted to keep the properties intact that were set for the cell in Interface Builder.
I solved the task by using NSKeyedArchiver, which is made to store and restore an object's properties.
Since NSTextFieldCell implements initWithCoder, it supports the archiver functions, and therefore I could use this code to init my subclass from the other's properties:
- (id)initWithCell:(NSCell *)cell {
// Use NSArchiver to copy the NSCell's properties into our subclass
NSMutableData *data = [NSMutableData data];
NSKeyedArchiver *arch = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
[cell encodeWithCoder:arch];
[arch finishEncoding];
NSKeyedUnarchiver *ua = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
self = [self initWithCoder:ua];
// Here I'd set up additional properties of my own class
return self;
}

NSString value nil inside onEnterTransitionDidFinish method

I guess its a very basic memory concept. But couldn't figure it out what happens with below case. Any insight would be helpful.
This could be similar to Problems with NSString inside viewWillDisappear
But I wanted to know why there requires a #property. How can we do it without taking #property. Please provide some inside view.
in .h I have NSString *someString
in .mm (this is my non-ARC cocos2d+box2d game scene)
-(id)initWithString:(NSString *)tempString
{
if(self = [super init])
{
someString = [[NSString allo]init];
someString = tempString;
}
return self;
}
-(void)onEnterTransitionDidfinish
{
[super onEnterTransitionDidfinish];
NSLog("The String is %#",someString);//Becomes nil here
}
-(void)printString
{
NSLog(#"The String is %#",someString);//This works fine
}
If you are not using ARC then you need to learn a lot more about memory management.
The following two lines:
someString = [[NSString allo]init];
someString = tempString;
should be:
someString = [tempString copy]; // or [tempString retain];
And be sure you call [someString release] in your dealloc method.
BTW - you are not using a property. someString is declared as an instance variable, not a property.

Changing language of iOS app [duplicate]

When I change the app used language independently on the device language it doesn't take effect until I close the app and restart it. How to not require app to be restarted for loading all nib files and .strings files again depending on the selected language?
I use this to change language at runtime:
NSArray* languages = [NSArray arrayWithObjects:#"ar", #"en", nil];
[[NSUserDefaults standardUserDefaults] setObject:languages forKey:#"AppleLanguages"];
This works for me :
Swift 4 :
Create a file named BundleExtension.swift and add the following code to it -
var bundleKey: UInt8 = 0
class AnyLanguageBundle: Bundle {
override func localizedString(forKey key: String,
value: String?,
table tableName: String?) -> String {
guard let path = objc_getAssociatedObject(self, &bundleKey) as? String,
let bundle = Bundle(path: path) else {
return super.localizedString(forKey: key, value: value, table: tableName)
}
return bundle.localizedString(forKey: key, value: value, table: tableName)
}
}
extension Bundle {
class func setLanguage(_ language: String) {
defer {
object_setClass(Bundle.main, AnyLanguageBundle.self)
}
objc_setAssociatedObject(Bundle.main, &bundleKey, Bundle.main.path(forResource: language, ofType: "lproj"), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
Now whenever you need to change the language call this method :
func languageButtonAction() {
// This is done so that network calls now have the Accept-Language as "hi" (Using Alamofire) Check if you can remove these
UserDefaults.standard.set(["hi"], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
// Update the language by swaping bundle
Bundle.setLanguage("hi")
// Done to reintantiate the storyboards instantly
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
UIApplication.shared.keyWindow?.rootViewController = storyboard.instantiateInitialViewController()
}
I had a similar requirement for a Kiosk mode iPad app with tabbed navigation. Not only did the app need to support on-the-fly language changes, but had to do so knowing that most of the tabs were already loaded from the nibs since the app was only restarted (on average) about once a week when a new version was loaded.
I tried several suggestions to leverage the existing Apple localization mechanisms and they all had serious drawbacks, including wonky support in XCode 4.2 for localized nibs -- my IBoutlet connection variables would appear to be set correctly in IB, but at runtime they would often be null!?
I wound up implementing a class that mimicked the Apple NSLocalizedString class but which could handle runtime changes, and whenever a language change was made by a user my class posted a notification. Screens that needed localized strings (and images) to change declared a handleLocaleChange method, which was called at viewDidLoad, and whenever the LocaleChangedNotification was posted.
All of my buttons and graphics were designed to be language independent, although the title text and label text was typically updated in response to locale changes. If I had to change images, I could have done so in the handleLocaleChange methods for each screen, I suppose.
Here is the code. It includes some support for nib/bundle paths which I actually don't use in the final project.
MyLanguage.h
//
// MyLanguage.h
//
//
#import <Foundation/Foundation.h>
#define DEFAULT_DICTIONARY_FOR_STRINGS #""
#define ACCESSING_ALTERNATE_DICTIONARY_SETS_DEFAULT 1
#define LANGUAGE_ENGLISH_INT 0
#define LANGUAGE_SPANISH_INT 1
#define LANGUAGE_ENGLISH_SHORT_ID #"en"
#define LANGUAGE_SPANISH_SHORT_ID #"es"
#define LANGUAGE_CHANGED_NOTIFICATION #"LANGUAGE_CHANGED"
#interface MyLanguage : NSObject
{
NSString *currentLanguage;
NSDictionary *currentDictionary;
NSBundle *currentLanguageBundle;
}
+(void) setLanguage:(NSString *)languageName;
+(NSString *)stringFor:(NSString *)srcString forLanguage:(NSString *)languageName;
+(NSString *)stringFor:(NSString *)srcString;
+ (MyLanguage *)singleton;
#property (nonatomic, retain) NSBundle *currentLanguageBundle;
#property (nonatomic, retain) NSString *currentLanguage;
#property (nonatomic, retain) NSDictionary *currentDictionary;
#end
MyLanguage.m:
//
// MyLanguage.m
#import "MyLanguage.h"
#import "Valet.h"
#define GUI_STRING_FILE_POSTFIX #"GUIStrings.plist"
#implementation MyLanguage
#synthesize currentLanguage;
#synthesize currentDictionary;
#synthesize currentLanguageBundle;
+(NSDictionary *)getDictionaryNamed:(NSString *)languageName
{
NSDictionary *results = nil;
// for now, we store dictionaries in a PLIST with the same name.
NSString *dictionaryPlistFile = [languageName stringByAppendingString:GUI_STRING_FILE_POSTFIX];
NSString *plistBundlePath = [Valet getBundlePathForFileName:dictionaryPlistFile];
if ( [[NSFileManager defaultManager] fileExistsAtPath:plistBundlePath] )
{
// read it into a dictionary
NSDictionary *newDict = [NSDictionary dictionaryWithContentsOfFile:plistBundlePath];
results = [newDict valueForKey:#"languageDictionary"];
}// end if
return results;
}
+(NSString *)stringFor:(NSString *)srcString forDictionary:(NSString *)languageName;
{
MyLanguage *gsObject = [MyLanguage singleton];
// if default dictionary matches the requested one, use it.
if ([gsObject.currentLanguage isEqualToString:languageName])
{
// use default
return [MyLanguage stringFor:srcString];
}// end if
else
{
// get the desired dictionary
NSDictionary *newDict = [MyLanguage getDictionaryNamed:languageName];
// default is not desired!
if (ACCESSING_ALTERNATE_DICTIONARY_SETS_DEFAULT)
{
gsObject.currentDictionary = newDict;
gsObject.currentLanguage = languageName;
return [MyLanguage stringFor:srcString];
}// end if
else
{
// use current dictionary for translation.
NSString *results = [gsObject.currentDictionary valueForKey:srcString];
if (results == nil)
{
return srcString;
}// end if
return results;
}
}
}
+(void) setLanguage:(NSString *)languageName;
{
MyLanguage *gsObject = [MyLanguage singleton];
// for now, we store dictionaries in a PLIST with the same name.
// get the desired dictionary
NSDictionary *newDict = [MyLanguage getDictionaryNamed:languageName];
gsObject.currentDictionary = newDict;
gsObject.currentLanguage = languageName;
// now set up the bundle for nibs
NSString *shortLanguageIdentifier = #"en";
if ([languageName contains:#"spanish"] || [languageName contains:#"espanol"] || [languageName isEqualToString:LANGUAGE_SPANISH_SHORT_ID])
{
shortLanguageIdentifier = LANGUAGE_SPANISH_SHORT_ID;
}// end if
else
shortLanguageIdentifier = LANGUAGE_ENGLISH_SHORT_ID;
// NSArray *languages = [NSArray arrayWithObject:shortLanguageIdentifier];
// [[NSUserDefaults standardUserDefaults] setObject:languages forKey:#"AppleLanguages"];
//
NSString *path= [[NSBundle mainBundle] pathForResource:shortLanguageIdentifier ofType:#"lproj"];
NSBundle *languageBundle = [NSBundle bundleWithPath:path];
gsObject.currentLanguageBundle = languageBundle;
[[NSNotificationCenter defaultCenter] postNotificationName:LANGUAGE_CHANGED_NOTIFICATION object:nil];
}
+(NSString *)stringFor:(NSString *)srcString;
{
MyLanguage *gsObject = [MyLanguage singleton];
// default is to do nothing.
if (gsObject.currentDictionary == nil || gsObject.currentLanguage == nil || [gsObject.currentLanguage isEqualToString:DEFAULT_DICTIONARY_FOR_STRINGS] )
{
return srcString;
}// end if
// use current dictionary for translation.
NSString *results = [gsObject.currentDictionary valueForKey:srcString];
if (results == nil)
{
return srcString;
}// end if
return results;
}
#pragma mark -
#pragma mark Singleton methods
static MyLanguage *mySharedSingleton = nil;
-(void) lateInit;
{
}
// PUT THIS METHOD DECLARATION INTO THE HEADER
+ (MyLanguage *)singleton;
{
if (mySharedSingleton == nil) {
mySharedSingleton = [[super allocWithZone:NULL] init];
[mySharedSingleton lateInit];
}
return mySharedSingleton;
}
+ (id)allocWithZone:(NSZone *)zone
{ return [[self singleton] retain]; }
- (id)copyWithZone:(NSZone *)zone
{ return self; }
- (id)retain
{ return self; }
- (NSUInteger)retainCount //denotes an object that cannot be released
{ return NSUIntegerMax; }
- (oneway void)release //do nothing
{ }
- (id)autorelease
{ return self; }
#end
Don't rely on strings that you have set in your nib file. Use your nib only for layout & setup of views. Any string that is shown to the user (button text, etc) needs to be in your Localizable.strings files, and when you load your nib you need to set the text on the corresponding view/control accordingly.
To get the bundle for the current language:
NSString *path = [[NSBundle mainBundle] pathForResource:currentLanguage ofType:#"lproj"];
if (path) {
NSBundle *localeBundle = [NSBundle bundleWithPath:path];
}
And to use the bundle to obtain your localized strings:
NSLocalizedStringFromTableInBundle(stringThatNeedsToBeLocalized, nil, localeBundle, nil);
Also for date formatting, you might want to look into
[NSDateFormatter dateFormatFromTemplate:#"HH:mm:ss"" options:0 locale:locale];
To use that you will need to create a NSLocale for the corresponding language/country which you wish to use.
Heres what I did. I guess the trick was to use NSLocalizedStringFromTableInBundle instead of NSLocalizedString.
For all strings, use this
someLabel.text = NSLocalizedStringFromTableInBundle(#"Your String to be localized, %#",nil,self.localeBundle,#"some context for translators");
To change language, run this code
NSString * language = #"zh-Hans"; //or whatever language you want
NSString *path = [[NSBundle mainBundle] pathForResource:language ofType:#"lproj"];
if (path) {
self.localeBundle = [NSBundle bundleWithPath:path];
}
else {
self.localeBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:#"en" ofType:#"lproj"] ];
}
After this, you will likely want to call whatever update code to update the strings to the new languages, for e.g. run this again
someLabel.text = NSLocalizedStringFromTableInBundle(#"Your String to be localized, %#",nil,self.localeBundle,#"some context for translators");
Thats all. No need restart app. Compatible with system settings as well (if you set a language through iOS settings, it will work too). No need external library. No need jailbreak. And it works with genstrings too.
Of course, you should still do the usual for your app settings to persist:
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:#"zh-Hans", nil] forKey:#"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize];
(and do a check in your viewDidLoad or something)
NSString * language = [[NSLocale preferredLanguages] objectAtIndex:0];
NSString *path = [[NSBundle mainBundle] pathForResource:language ofType:#"lproj"];
if (path) {
self.localeBundle = [NSBundle bundleWithPath:path];
}
else {
self.localeBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:#"en" ofType:#"lproj"] ];
}
You should create your own macro similar to NSLocalizedString but bases the bundle it chooses a string from on a NSUserDefaults value you set (i.e. don't worry about what the value of apples language defaults value is)
When you change the language you should send out a notification, which view controllers, views etc should listen for and refresh themselves

iOS - custom initialization method for view controllers when using storyboard

I've read several posts similar to this one but I found them too specific. What I really want is a more general answer. According to Apple's view controller programming guide, viewDidLoad: should be used to "Allocating or loading data to be displayed in your view". If I have some data that has nothing to do with display, where should I initialize them?
Some posts suggests that initialization could be done in initWithCoder: when the view controller is initialized via a storyboard. I've tried to initialize an array in initWithCoder:, but after that it turned out that the array is still empty. So can we write a designated initializer to initialize this kind of data?
Here is the code:
- (id)initWithCoder:(NSCoder *)aDecoder
{
if (self = [super initWithCoder:aDecoder]) {
// load notes
NSString * path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
_notes = [[PWCNotes alloc] initNotesWithFilename:self.docTitle path:path numberOfPages:self.numberOfPages];
_index = 0;
}
return self;
}
Here is the designated initializer method for PWCNotes
- (id)initNotesWithFilename:(NSString *)fileName path:(NSString *)path numberOfPages:(int)numberOfPages
{
if (!(self = [super init])) {
return nil;
}
_filePath = [path stringByAppendingString:[NSString stringWithFormat:#"/%#/notes.txt", fileName]];
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:self.filePath];
if (!exists)
{
// if file does not exist, create one and initialize the content
_notes = [[NSMutableArray alloc] init];
[[NSFileManager defaultManager] createFileAtPath:self.filePath contents:nil attributes:nil];
NSString * emptyString = #"Add Notes Here!";
for (int i = 0; i < numberOfPages; ++i)
{
[self.notes addObject:emptyString];
}
// write content of the array to the file
[self.notes writeToFile:self.filePath atomically:YES];
}
else
{
// otherwise, load it from the text file
_notes = [[NSMutableArray alloc] initWithContentsOfFile:self.filePath];
}
return self;
}
PWCNotes class has as a property a mutable array of NSString *s. When I call [self.notes.notes getObjectAtIndex:self.index], an NSRangeException is thrown, saying that I'm trying to access the object at index 0 in an empty array. Am I missing something?
viewDidLoad is the best place if you need to use the data only once the view appears, which is usually the case for View Controllers, as they only exists for managing views.
It's the best place because it is the one that's called in any case, no matter how the class got initialized.
If you really wanted to have the data ready earlier, you could implement an +initialize or +load method (NSObject +load and +initialize - What do they do?) instead, but that's not really what you should do in a View Controller.

Check whether an object was created inside a loop or not

is there any way in Objective-C to check whether an Object has been created inside a loop (while, for)?
Thanks in advance.
NSString *obj = nil;
while()
{
//Create object
obj = [[NSString alloc] init];
}
//check obj is nil or not
if(nil == obj)
{
// obj not created
}
Yes but for an accurate answer can you tell us what the object is and when it is declared? Can you post the code you have?
int x=0;
while (x<3) {
NSString *i = #"hello world";
x++;
}
NSLog(#"i is %#", i) // i is only declared inside the while loop so not available here
Alternatively,
int x=0;
NSString *i;
while (x<3) {
i = #"hello world";
x++;
}
NSLog(#"i is %#", i); // i is declared beforehand outside the while loop so is available here
If you then need to act on whether it's been created or not use Anil's answer but it's the scope that's important here
I don't think you can know if it was created in a loop, but because you are writing the code where the object will be created in a loop you could call a special init method...
SpecialClass * obj = [[SpecialClass alloc] init];
while (isTrue)
{
SpecialClass * loopObj = [[SpecialClass alloc] initCreatedByLoop];
// Do whats needed
}
and in your SpecialClass you create a specific initialiser...
#implementation SpecialClass
-(id)initCreatedByLoop {
self = [super init];
if (self) {
// What ever you want to do
}
return self;
}

Resources