ObjectiveC- এ ভেরিয়েবলের অবস্থানের ঘোষণা / সংজ্ঞা?


113

আইওএস অ্যাপস এবং উদ্দেশ্য সি নিয়ে কাজ শুরু করার পর থেকেই আমি সত্যিই বিভিন্ন স্থানের দ্বারা আশ্চর্য হয়েছি যেখানে কেউ ভেরিয়েবলগুলি ঘোষণা ও সংজ্ঞা দিতে পারে। একদিকে আমাদের theতিহ্যবাহী সি পদ্ধতির রয়েছে, অন্যদিকে আমাদের কাছে নতুন ওজেক্টিভ সি-র নির্দেশনা রয়েছে যা এর ওওকে যুক্ত করে। আপনি কি আমাকে সেরা অনুশীলন এবং পরিস্থিতি বুঝতে সাহায্য করতে পারেন যেখানে আমি এই স্থানগুলি আমার চলকগুলির জন্য ব্যবহার করতে এবং সম্ভবত আমার বর্তমান উপলব্ধিটি সংশোধন করতে চাই?

এখানে একটি নমুনা শ্রেণি (। ঘন্টা এবং মি।):

#import <Foundation/Foundation.h>

// 1) What do I declare here?

@interface SampleClass : NSObject
{
    // 2) ivar declarations
    // Pretty much never used?
}

// 3) class-specific method / property declarations

@end

এবং

#import "SampleClass.h"

// 4) what goes here?

@interface SampleClass()

// 5) private interface, can define private methods and properties here

@end

@implementation SampleClass
{
    // 6) define ivars
}

// 7) define methods and synthesize properties from both public and private
//    interfaces

@end
  • 1 এবং 4 এর আমার বোধগম্যতা হ'ল সেগুলি সি-স্টাইলের ফাইল-ভিত্তিক ঘোষণা এবং সংজ্ঞা যা শ্রেণীর ধারণা সম্পর্কে যা কিছু আছে তা বোঝে না এবং এইভাবে তারা সিটিতে কীভাবে ব্যবহৃত হবে তা ব্যবহার করতে হবে আমি সেগুলি দেখেছি them স্ট্যাটিক ভেরিয়েবল-ভিত্তিক সিলেটলেটগুলি বাস্তবায়নের জন্য ব্যবহৃত হয়েছিল। আমি অনুপস্থিত অন্য কোন সুবিধাজনক ব্যবহার আছে?
  • আইওএসের সাথে কাজ করা থেকে আমার গ্রহণযোগ্যতাটি হ'ল আইভরগুলি @ সায়েন্টেসাইজ নির্দেশাবলীর বাইরে সম্পূর্ণ পর্যায়ক্রমে বাইরে চলে গেছে এবং এভাবে বেশিরভাগ ক্ষেত্রে উপেক্ষা করা যেতে পারে। এটাই কি?
  • 5 সম্পর্কিত: কেন আমি কখনও ব্যক্তিগত ইন্টারফেসে পদ্ধতিগুলি ঘোষণা করতে চাই? আমার ব্যক্তিগত ক্লাসের পদ্ধতিগুলি ইন্টারফেসে কোনও ঘোষণা ছাড়াই ঠিক সূক্ষ্ম সংকলন করে বলে মনে হচ্ছে। এটি কি বেশিরভাগই পঠনযোগ্যতার জন্য?

ধন্যবাদ একগুচ্ছ, লোকেরা!

উত্তর:


154

আমি আপনার বিভ্রান্তি বুঝতে পারি বিশেষত এক্সকোডের সাম্প্রতিক আপডেটগুলি এবং নতুন এলএলভিএম সংকলক আইভার এবং বৈশিষ্ট্যগুলি ঘোষণার পদ্ধতিতে পরিবর্তন করেছে।

"আধুনিক" অবজেক্টিভ-সি এর আগে ("পুরাতন" ওবজ-সি 2.0 তে) আপনার খুব পছন্দ ছিল না। কোঁকড়া বন্ধনীগুলির মধ্যে শিরোলেখগুলিতে ইনস্ট্যান্স ভেরিয়েবলগুলি ঘোষিত হত { }:

// MyClass.h
@interface MyClass : NSObject {
    int myVar;
}
@end

আপনি কেবলমাত্র প্রয়োগের ক্ষেত্রে এই পরিবর্তনশীলগুলিতে অ্যাক্সেস করতে সক্ষম হয়েছিলেন তবে অন্যান্য ক্লাস থেকে নয়। এটি করতে, আপনাকে অ্যাকসেসর পদ্ধতিগুলি ঘোষণা করতে হয়েছিল, এটি দেখতে এমন কিছু দেখাচ্ছে:

// MyClass.h
@interface MyClass : NSObject {
    int myVar;
}

- (int)myVar;
- (void)setMyVar:(int)newVar;

@end


// MyClass.m
@implementation MyClass

- (int)myVar {
   return myVar;
}

- (void)setMyVar:(int)newVar {
   if (newVar != myVar) {
      myVar = newVar;
   }
}

@end

আপনি অন্য ক্লাস থেকে এই উদাহরণটি পরিবর্তনশীল পেতে এবং সেট করতে সক্ষম হন, বার্তা পাঠানোর জন্য সাধারণ বর্গাকার বন্ধনী বাক্য গঠন ব্যবহার করে (কল পদ্ধতি):

// OtherClass.m
int v = [myClass myVar];  // assuming myClass is an object of type MyClass.
[myClass setMyVar:v+1];

ম্যানুয়ালি ঘোষণা এবং বাস্তবায়নের যে অ্যাকসেসর পদ্ধতি বেশ বিরক্তিকর হয়েছে, কারণ @propertyএবং @synthesizeস্বয়ংক্রিয়ভাবে অ্যাকসেসর পদ্ধতি জেনারেট করতে চালু করা হয়েছে:

// MyClass.h
@interface MyClass : NSObject {
    int myVar;
}
@property (nonatomic) int myVar;
@end

// MyClass.m
@implementation MyClass
@synthesize myVar;
@end

ফলাফলটি আরও পরিষ্কার এবং সংক্ষিপ্ত কোড। অ্যাক্সেসর পদ্ধতিগুলি আপনার জন্য প্রয়োগ করা হবে এবং আপনি এখনও আগের মতো বন্ধনী বাক্য গঠন ব্যবহার করতে পারেন। তবে অতিরিক্ত হিসাবে, আপনি বৈশিষ্ট্য অ্যাক্সেস করতে ডট সিনট্যাক্সও ব্যবহার করতে পারেন:

// OtherClass.m
int v = myClass.myVar;   // assuming myClass is an object of type MyClass.
myClass.myVar = v+1;

এক্সকোড ৪.৪ থেকে আপনাকে নিজেকে আর কোনও পরিবর্তনশীল ঘোষিত করতে হবে না এবং @synthesizeআপনিও এড়িয়ে যেতে পারেন । আপনি যদি আইভার ঘোষণা না করেন তবে সংকলকটি এটি আপনার জন্য যুক্ত করবে এবং এটি আপনাকে ব্যবহার না করে অ্যাকসেসর পদ্ধতিগুলিও উত্পন্ন করবে @synthesize

স্বয়ংক্রিয়ভাবে উত্পন্ন আইভারের ডিফল্ট নাম হল নাম বা আপনার সম্পত্তি আন্ডারস্কোর দিয়ে শুরু। আপনি ব্যবহার করে উত্পন্ন আইভারের নামটি পরিবর্তন করতে পারেন@synthesize myVar = iVarName;

// MyClass.h
@interface MyClass : NSObject 
@property (nonatomic) int myVar;
@end

// MyClass.m
@implementation MyClass
@end

এটি উপরের কোড হিসাবে ঠিক কাজ করবে। সামঞ্জস্যতার কারণে আপনি এখনও শিরোনামে ivars ঘোষণা করতে পারেন। তবে যে কারণে আপনি এটি করতে চান (এবং কোনও সম্পত্তি ঘোষণা না করা) তার একমাত্র কারণটি হল একটি ব্যক্তিগত ভেরিয়েবল তৈরি করা, আপনি এখন এটি প্রয়োগের ফাইলটিতেও করতে পারেন এবং এটি পছন্দসই উপায়।

@interfaceবাস্তবায়ন ফাইলে থাকা একটি ব্লক আসলে একটি এক্সটেনশন এবং ঘোষিত পদ্ধতিগুলি (আর প্রয়োজন হয় না) এবং (পুনরায়) সম্পত্তি ঘোষণার জন্য ব্যবহার করতে পারে। আপনি উদাহরণস্বরূপ readonlyআপনার শিরোনামে একটি সম্পত্তি ঘোষণা করতে পারে ।

@property (nonatomic, readonly) myReadOnlyVar;

এবং readwriteকেবল আইভারে সরাসরি অ্যাক্সেসের মাধ্যমে নয়, সম্পত্তি সিনট্যাক্স ব্যবহার করে এটি সেট করতে সক্ষম হওয়ায় এটি আপনার বাস্তবায়ন ফাইলটিতে পুনরায় ঘোষিত করুন।

সম্পূর্ণরূপে যেকোন @interfaceবা @implementationব্লকের বাইরে ভেরিয়েবলগুলি ঘোষণা করার জন্য , হ্যাঁ সেগুলি সরল সি ভেরিয়েবল এবং ঠিক একইভাবে কাজ করে।


2
দুর্দান্ত উত্তর! এছাড়াও নোট: stackoverflow.com/questions/9859719/...
nycynik

44

প্রথমে @ ড্রামারবি'র উত্তরটি পড়ুন। এটি হুইস এবং আপনার সাধারণত কি করা উচিত তার একটি ভাল ওভারভিউ। আপনার নির্দিষ্ট প্রশ্নগুলির বিষয়টি মাথায় রেখে:

#import <Foundation/Foundation.h>

// 1) What do I declare here?

এখানে কোন আসল পরিবর্তনীয় সংজ্ঞা দেওয়া হয় না (আপনি কী করছেন ঠিক তা যদি জানেন তবে এটি কখনই করবেন না প্রযুক্তিগতভাবে এটি আইনী)। আপনি বিভিন্ন ধরণের জিনিস সংজ্ঞায়িত করতে পারেন:

  • typdefs
  • enums
  • externs

বাহ্যিকগুলি ভেরিয়েবল ঘোষণার মতো দেখতে লাগে তবে এটিকে অন্য কোথাও ঘোষণা করার কেবলমাত্র প্রতিশ্রুতি। ওবিজেসিতে, এগুলি কেবল ধ্রুবক হিসাবে ঘোষণা করতে ব্যবহৃত হয় এবং সাধারণত কেবল স্ট্রিং ধ্রুবক। এই ক্ষেত্রে:

extern NSString * const MYSomethingHappenedNotification;

আপনি তখন আপনার .mফাইলে আসল ধ্রুবকটি ঘোষণা করবেন:

NSString * const MYSomethingHappenedNotification = @"MYSomethingHappenedNotification";

@interface SampleClass : NSObject
{
    // 2) ivar declarations
    // Pretty much never used?
}

ড্রামারবি দ্বারা উল্লিখিত হিসাবে, এটি উত্তরাধিকার। এখানে কিছু রাখবেন না।


// 3) class-specific method / property declarations

@end

হাঁ।


#import "SampleClass.h"

// 4) what goes here?

বাহ্যিক ধ্রুবকগুলি, উপরে বর্ণিত হিসাবে। স্ট্যাটিক ভেরিয়েবলগুলি ফাইল করতে পারেন এখানে। এগুলি অন্যান্য ভাষায় শ্রেণিবদ্ধের সমতুল্য।


@interface SampleClass()

// 5) private interface, can define private methods and properties here

@end

হাঁ


@implementation SampleClass
{
    // 6) define ivars
}

তবে খুব কমই। প্রায় সবসময় আপনার পক্ষে ঝাঁকুনি (এক্সকোড) আপনার পক্ষে ভেরিয়েবলগুলি তৈরি করতে দেওয়া উচিত। ব্যতিক্রমগুলি সাধারণত নন-ওজেসিসি আইভার্স (যেমন কোর ফাউন্ডেশন অবজেক্টস, এবং বিশেষত সি ++ অবজেক্টগুলি যদি এটি একটি ওজসি ++ শ্রেণি হয়), বা আইভারগুলির অদ্ভুত স্টোরেজ শব্দার্থক (আইভারগুলির মতো যা কোনও কারণে কোনও সম্পত্তির সাথে মেলে না) around


// 7) define methods and synthesize properties from both public and private
//    interfaces

সাধারণত আপনার আর @nthesised করা উচিত নয়। ঝনঝন (Xcode) এটি আপনার জন্য করবে এবং আপনার তা দেওয়া উচিত।

গত কয়েক বছর ধরে, জিনিসগুলি নাটকীয়ভাবে সহজতর হয়েছে। পার্শ্ব-প্রতিক্রিয়াটি হ'ল এখন তিনটি পৃথক যুগ (ফ্রেগিলি এবিআই, নন-ভঙ্গুর এবিআই, নন-ভঙ্গুর এবিআই + অটো-সিন্থেসিজ) রয়েছে। সুতরাং আপনি যখন পুরানো কোডটি দেখেন তখন এটি কিছুটা বিভ্রান্তিকর হতে পারে। এভাবে সরলতা থেকে উদ্ভূত বিভ্রান্তি: ডি


শুধু ভাবছি, তবে কেন আমরা স্পষ্টভাবে সংশ্লেষ করা উচিত না? আমি এটি করি কারণ আমি আমার কোডটি বোঝা সহজ করে পাই, বিশেষত যখন কিছু বৈশিষ্ট্যে সংশ্লেষিত অ্যাক্সেসর রয়েছে এবং কিছুতে কাস্টম বাস্তবায়ন হয়, যেহেতু আমি সংশ্লেষকরণে অভ্যস্ত। সুস্পষ্ট সংশ্লেষণের কোনও ত্রুটি আছে কি?
মেটেবল

এটি ডকুমেন্টেশন হিসাবে ব্যবহার করতে সমস্যা হ'ল এটি আসলে কিছুই নথিভুক্ত করে না। সংশ্লেষ ব্যবহার করা সত্ত্বেও, আপনি এক বা উভয় প্রবেশকারীকে ওভাররাইড করে থাকতে পারেন। সিনথেসাইজ লাইন থেকে সত্যিই দরকারী কিছু বলার উপায় নেই। কোনও ডকুমেন্টেশনের চেয়ে খারাপ বিষয় হ'ল বিভ্রান্তিকর ডকুমেন্টেশন। ছেড়ে দাও।
রব নেপিয়ার

3
কেন # 6 বিরল? এটি কি কোনও ব্যক্তিগত ভেরিয়েবল পাওয়ার সহজতম উপায় নয়?
pfrank

একটি ব্যক্তিগত সম্পত্তি পাওয়ার সবচেয়ে সহজ এবং সর্বোত্তম উপায় হ'ল # 5।
রব নেপিয়ার

1
@ রবনেপিয়ার এখনও কখনও কখনও @ সিনথেসাইজ ব্যবহার করা প্রয়োজন (যেমন কোনও সম্পত্তি যদি কেবলমাত্র পাঠ্যরূপে এর অ্যাক্সেসরকে ওভাররাইড করা থাকে)
অ্যান্ডি

6

আমিও বেশ নতুন, তাই আশা করি আমি কিছুই আপ করবো না।

1 এবং 4: সি স্টাইলের গ্লোবাল ভেরিয়েবলগুলি: তাদের ফাইলের প্রশস্ত সুযোগ রয়েছে। উভয়ের মধ্যে পার্থক্যটি হ'ল যেহেতু তারা প্রশস্ত ফাইল রয়েছে, তাই প্রথমটি যে কেউ শিরোনাম আমদানি করার সময় দ্বিতীয়টির জন্য উপলব্ধ থাকবে।

2: উদাহরণ ভেরিয়েবল। বেশিরভাগ উদাহরণের ভেরিয়েবলগুলি বৈশিষ্ট্যগুলি ব্যবহার করে অ্যাক্সেসরের মাধ্যমে সংশ্লেষিত এবং পুনরুদ্ধার / সেট করা হয় কারণ এটি মেমরি পরিচালনাকে সুন্দর এবং সহজ করে তোলে, পাশাপাশি আপনাকে বোঝার জন্য সহজ বিন্দুর স্বরলিপি দেয়।

6: বাস্তবায়ন আইভারগুলি কিছুটা নতুন। এটি ব্যক্তিগত আইভর রাখার জন্য একটি ভাল জায়গা, যেহেতু আপনি কেবল সর্বজনীন শিরোনামে যা প্রয়োজন তা প্রকাশ করতে চান তবে সাবক্লাসগুলি এফএইকে উত্তরাধিকার সূত্রে পায় না।

3 এবং 7: সর্বজনীন পদ্ধতি এবং সম্পত্তি ঘোষণা, তারপরে বাস্তবায়ন।

5: ব্যক্তিগত ইন্টারফেস। জিনিসগুলি পরিষ্কার রাখতে এবং এক ধরণের ব্ল্যাক বক্স এফেক্ট তৈরি করতে আমি যখনই পারি সর্বদা ব্যক্তিগত ইন্টারফেস ব্যবহার করি। তাদের যদি এ সম্পর্কে জানার দরকার না হয় তবে এটি সেখানে রাখুন। আমি এটি পঠনযোগ্যতার জন্যও করি, অন্য কোনও কারণ আছে কিনা তা জানি না।


1
আপনি কোনও আপত্তি করেছেন বলে মনে করবেন না :) কয়েকটি মন্তব্য - # 1 & # 4 এসএসপি # 4 দিয়ে প্রায়শই আপনি স্থির স্টোরেজ ভেরিয়েবলগুলি দেখতে পান। # 1 প্রায়শই আপনি নির্ধারিত বাহ্যিক স্টোরেজ এবং তারপরে আসল স্টোরেজটি # 4 এ বরাদ্দ পাবেন। # 2) কেবলমাত্র যদি কোনও সাবক্লাসের যে কোনও কারণেই এটির প্রয়োজন হয়। # 5 টি আর প্রাইভেট পদ্ধতি ঘোষণা করার জন্য ফরওয়ার্ড করার দরকার নেই।
কার্ল ভয়েজি

হ্যাঁ, আমি নিজেই ঘোষণা ঘোষণা করেছিলাম। এটি একটি সতর্কতা দিতেন যদি কোনও ব্যক্তিগত পদ্ধতি অন্যটিকে ডেকে বলে যে এটির পরে কোনও ঘোষণা ছাড়াই সংজ্ঞায়িত করা হয়েছিল, তাই না? যখন এটি আমাকে সতর্ক না করে আমি একপ্রকার অবাক হয়েছিলাম।
মেটাবেল

হ্যাঁ এটি সংকলকের নতুন অংশ। তারা ইদানীং সত্যিই অনেক অগ্রগতি করেছে।
কার্ল ভিয়েজি

6

এটি উদ্দেশ্যমূলক-সি-তে ঘোষণা করা সমস্ত ধরণের ভেরিয়েবলের একটি উদাহরণ। পরিবর্তনশীল নামটি এর অ্যাক্সেস নির্দেশ করে।

ফাইল: প্রাণী

@interface Animal : NSObject
{
    NSObject *iProtected;
@package
    NSObject *iPackage;
@private
    NSObject *iPrivate;
@protected
    NSObject *iProtected2; // default access. Only visible to subclasses.
@public
    NSObject *iPublic;
}

@property (nonatomic,strong) NSObject *iPublic2;

@end

ফাইল: প্রাণী.মি

#import "Animal.h"

// Same behaviour for categories (x) than for class extensions ().
@interface Animal(){
@public
    NSString *iNotVisible;
}
@property (nonatomic,strong) NSObject *iNotVisible2;
@end

@implementation Animal {
@public
    NSString *iNotVisible3;
}

-(id) init {
    self = [super init];
    if (self){
        iProtected  = @"iProtected";
        iPackage    = @"iPackage";
        iPrivate    = @"iPrivate";
        iProtected2 = @"iProtected2";
        iPublic     = @"iPublic";
        _iPublic2    = @"iPublic2";

        iNotVisible   = @"iNotVisible";
        _iNotVisible2 = @"iNotVisible2";
        iNotVisible3  = @"iNotVisible3";
    }
    return self;
}

@end

নোট করুন যে আইনটভিজিবল ভেরিয়েবলগুলি অন্য কোনও শ্রেণীর থেকে দৃশ্যমান নয়। এই দৃশ্যমানতা ইস্যু, তাই তাদের সাথে প্রকাশক @propertyবা @publicএটা পরিবর্তন করে না।

কনস্ট্রাক্টরের অভ্যন্তরে পার্শ্ব প্রতিক্রিয়া এড়াতে @propertyআন্ডারস্কোর ব্যবহার করে ঘোষিত ভেরিয়েবলগুলি অ্যাক্সেস করা ভাল অভ্যাস self

চলকগুলি অ্যাক্সেস করার চেষ্টা করি।

ফাইল: গরু

#import "Animal.h"
@interface Cow : Animal
@end

ফাইল: Cow.m

#import "Cow.h"
#include <objc/runtime.h>

@implementation Cow

-(id)init {
    self=[super init];
    if (self){
        iProtected    = @"iProtected";
        iPackage      = @"iPackage";
        //iPrivate    = @"iPrivate"; // compiler error: variable is private
        iProtected2   = @"iProtected2";
        iPublic       = @"iPublic";
        self.iPublic2 = @"iPublic2"; // using self because the backing ivar is private

        //iNotVisible   = @"iNotVisible";  // compiler error: undeclared identifier
        //_iNotVisible2 = @"iNotVisible2"; // compiler error: undeclared identifier
        //iNotVisible3  = @"iNotVisible3"; // compiler error: undeclared identifier
    }
    return self;
}
@end

রানটাইম ব্যবহার করে আমরা এখনও দৃশ্যমান পরিবর্তনশীলগুলিতে অ্যাক্সেস করতে পারি।

ফাইল: Cow.m (অংশ 2)

@implementation Cow(blindAcess)

- (void) setIvar:(NSString*)name value:(id)value {
    Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]);
    object_setIvar(self, ivar, value);
}

- (id) getIvar:(NSString*)name {
    Ivar ivar = class_getInstanceVariable([self class], [name UTF8String]);
    id thing = object_getIvar(self, ivar);
    return thing;
}

-(void) blindAccess {
    [self setIvar:@"iNotVisible"  value:@"iMadeVisible"];
    [self setIvar:@"_iNotVisible2" value:@"iMadeVisible2"];
    [self setIvar:@"iNotVisible3" value:@"iMadeVisible3"];
    NSLog(@"\n%@ \n%@ \n%@",
          [self getIvar:@"iNotVisible"],
          [self getIvar:@"_iNotVisible2"],
          [self getIvar:@"iNotVisible3"]);
}

@end

আসুন দৃশ্যমান ভেরিয়েবলগুলি অ্যাক্সেস করার চেষ্টা করি।

ফাইল: main.m

#import "Cow.h"
#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
    @autoreleasepool {
        Cow *cow = [Cow new];
        [cow performSelector:@selector(blindAccess)];
    }
}

এই মুদ্রণ

iMadeVisible 
iMadeVisible2 
iMadeVisible3

নোট করুন যে আমি _iNotVisible2সাবক্লাসে ব্যক্তিগত যে ব্যাকিং আইভারটি অ্যাক্সেস করতে সক্ষম হয়েছি । অবজেক্টিভ-সিতে সমস্ত ভেরিয়েবলগুলি পড়া বা সেট করা যায়, এমনকি চিহ্নিত চিহ্নযুক্তগুলিও @privateব্যতিক্রম নয়।

আমি সম্পর্কিত বস্তু বা সি ভেরিয়েবলগুলি পৃথক পাখি হিসাবে অন্তর্ভুক্ত করি নি। সি ভেরিয়েবলের ক্ষেত্রে, কোনও পরিবর্তনশীল বাইরে সংজ্ঞায়িত @interface X{}বা @implementation X{}ফাইল স্কোপ এবং স্ট্যাটিক স্টোরেজ সহ সি ভেরিয়েবল।

আমি মেমরি পরিচালনা বৈশিষ্ট্যাবলী, বা পঠন / পাঠ্য রচয়িতা, গেটর / সেটার বৈশিষ্ট্যগুলি নিয়ে আলোচনা করিনি।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.