উদ্দেশ্য সি পদ্ধতির কলার সন্ধান করুন


90

কোনও নির্দিষ্ট কোডের রেখা নির্ধারণ করার উপায় আছে কি method?


আপনি কেন এটা করতে চান? যদি এটি ডিবাগিংয়ের জন্য হয় তবে আপনি উত্তরটি উত্পাদন করতে চাইলে তার চেয়ে আলাদা আলাদা আলাদা উত্তর রয়েছে (যার জন্য উত্তরটি সম্ভবত "না" হতে পারে))
নিকোলাস রিলে

4
আমি ডিবাগিংয়ের উত্তরটি
নেব

4
একটি উত্পাদন উত্তর আছে?
হরি করম সিং

উত্তর:


188

স্ট্যাকআই আশা করি এটির সাহায্য করে:

    NSString *sourceString = [[NSThread callStackSymbols] objectAtIndex:1];
    // Example: 1   UIKit                               0x00540c89 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1163
    NSCharacterSet *separatorSet = [NSCharacterSet characterSetWithCharactersInString:@" -[]+?.,"];
    NSMutableArray *array = [NSMutableArray arrayWithArray:[sourceString  componentsSeparatedByCharactersInSet:separatorSet]];
    [array removeObject:@""];

    NSLog(@"Stack = %@", [array objectAtIndex:0]);
    NSLog(@"Framework = %@", [array objectAtIndex:1]);
    NSLog(@"Memory address = %@", [array objectAtIndex:2]);
    NSLog(@"Class caller = %@", [array objectAtIndex:3]);
    NSLog(@"Function caller = %@", [array objectAtIndex:4]);

4
প্রিফিক্স.পিচ ফাইলে একটি ম্যাক্রোও তৈরি করে অ্যাপ্লিকেশন প্রতিনিধিটির কাছ থেকে চালিত করে। মজার বিষয় হচ্ছে, ক্লাস কলারটি ছিল: "<redacted>"
মেলভিন

4
আমার ক্ষেত্রে, সূচক 5 তে কিছুই নেই Thus সুতরাং এই কোডটি আমার অ্যাপ্লিকেশনটিকে ক্র্যাশ করেছে। এটি শেষ লাইনটি সরিয়ে দেওয়ার পরে কাজ করে। তবুও, এটি এখনও এত দুর্দান্ত যে এটির মূল্য +1!
ব্রায়ান

4
এটি দুর্দান্ত কাজ করে তবে আমরা "লাইন কলার" কীভাবে ব্যাখ্যা করব? আমার ক্ষেত্রে এটি একটি সংখ্যা দেখায়, উদাহরণস্বরূপ 91, তবে এটি 91 কেন? আমি যদি নীচে কলটিকে একটি নির্দেশনা সরিয়ে নিই, তবে এটি 136 দেখায় ... সুতরাং এই সংখ্যাটি কীভাবে গণনা করা হবে?
ম্যাক্সিম চেতুস্কা

@ পাটুর যদি পারফরম্যান্সে কোনও প্রভাব ফেলে তা নগণ্য, এনএসথ্রেডের ইতিমধ্যে সেই তথ্য রয়েছে, আপনি মূলত কেবল একটি অ্যারে অ্যাক্সেস করছেন এবং একটি নতুন তৈরি করছেন।
অস্কার গোমেজ

এটি ডিবাগ মোডে কাজ করছে, তবে এটি আইপিএ প্যাকেজে সংরক্ষণাগার দেওয়ার পরে, কল স্ট্যাকটি প্রত্যাশার মতো কাজ করছে না। আমি সবেমাত্র "কলস্ট্যাকসিম্বলস = 1 সিম্পল অ্যাপ 0x00000001002637a4 _Z8isxdigiti + 63136" পেয়েছি, "_জেড 8 আইসডডজিটি" হওয়া উচিত "অ্যামাজেন্ট অ্যাপ্লিকেশন অ্যাপ্লিকেশন: ডিফিনিশলঞ্চিং উইথঅ্যাপশনস:"
অ্যালানক লিউ

50

সম্পূর্ণরূপে অপ্টিমাইজড কোডে, কোনও নির্দিষ্ট পদ্ধতিতে কলার নির্ধারণের জন্য 100% নিশ্চিত কোনও উপায় নেই way সংকলকটি একটি টেল কল অপ্টিমাইজেশন নিয়োগ করতে পারে যেখানে সংকলক কার্যকরভাবে কলির জন্য কলারের স্ট্যাক ফ্রেমটিকে পুনরায় ব্যবহার করে।

এর উদাহরণ দেখতে, জিডিবি ব্যবহার করে প্রদত্ত যে কোনও পদ্ধতিতে ব্রেকপয়েন্ট নির্ধারণ করুন এবং ব্যাকট্র্যাসটি দেখুন। মনে রাখবেন যে প্রতিটি পদ্ধতি কল করার আগে আপনি obc_msgSend () দেখতে পাবেন না। এজন্য কারণ objc_msgSend () প্রতিটি পদ্ধতির প্রয়োগের জন্য একটি টেল কল করে।

আপনি যখন আপনার অ্যাপ্লিকেশনটি অপ-অপ্টিমাইজড করে ফেলতে পারেন, কেবলমাত্র এই একটি সমস্যা এড়াতে আপনার সিস্টেম লাইব্রেরির সমস্ত-অপ্টিমাইজড সংস্করণ প্রয়োজন।

এবং এটি কেবল একটি সমস্যা; বাস্তবে, আপনি জিজ্ঞাসা করছেন "আমি কীভাবে ক্র্যাশট্রেসার বা জিডিবি পুনরায় উদ্ভাবন করব?"। একটি খুব কঠিন সমস্যা যার উপর ক্যারিয়ার তৈরি হয়। যদি না আপনি "ডিবাগিং সরঞ্জামগুলি" আপনার ক্যারিয়ার হতে চান তবে আমি এই রাস্তায় নামার বিরুদ্ধে সুপারিশ করব।

আপনি আসলে কোন প্রশ্নের উত্তর দেওয়ার চেষ্টা করছেন?


4
হে ভগবান. এটি আমাকে পৃথিবীতে ফিরিয়ে এনেছে। প্রায় আক্ষরিক অর্থে। আমি একটি সম্পূর্ণ, সম্পর্কযুক্ত সমস্যা সমাধান করছিলাম। ধন্যবাদ জনাব!
নিমেশদেসই

11

ইন্ট্রোপড্রো দ্বারা সরবরাহিত উত্তর ব্যবহার করে , আমি এটি নিয়ে এসেছি:

#define CALL_ORIGIN NSLog(@"Origin: [%@]", [[[[NSThread callStackSymbols] objectAtIndex:1] componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"[]"]] objectAtIndex:1])

যা কেবল আমাকে মূল ক্লাস এবং ফাংশন ফিরিয়ে দেবে:

2014-02-04 16:49:25.384 testApp[29042:70b] Origin: [LCallView addDataToMapView]

পিএস - যদি ফাংশনটিকে পারফরমেসিটেক্টর ব্যবহার করে বলা হয়, ফলাফল হবে:

Origin: [NSObject performSelector:withObject:]

4
* তবে সচেতন থাকুন যে, কিছু ক্ষেত্রে এটিতে ফাংশন নাম থাকে না, নির্বাচকও সম্পাদন করে না এবং এইভাবে - কল করা হয় CALL_ORIGIN ক্র্যাশ। (সুতরাং, আমি পরামর্শ দিচ্ছি - আপনি যদি এই উদাহরণটি ব্যবহার করতে চান তবে এটি অস্থায়ীভাবে ব্যবহার করুন এবং তারপরে এটি অপসারণ করুন))
গুঁটিস ট্রুল্যান্ডস

6

সবেমাত্র একটি পদ্ধতি লিখেছেন যা এটি আপনার জন্য করবে:

- (NSString *)getCallerStackSymbol {

    NSString *callerStackSymbol = @"Could not track caller stack symbol";

    NSArray *stackSymbols = [NSThread callStackSymbols];
    if(stackSymbols.count >= 2) {
        callerStackSymbol = [stackSymbols objectAtIndex:2];
        if(callerStackSymbol) {
            NSMutableArray *callerStackSymbolDetailsArr = [[NSMutableArray alloc] initWithArray:[callerStackSymbol componentsSeparatedByString:@" "]];
            NSUInteger callerStackSymbolIndex = callerStackSymbolDetailsArr.count - 3;
            if (callerStackSymbolDetailsArr.count > callerStackSymbolIndex && [callerStackSymbolDetailsArr objectAtIndex:callerStackSymbolIndex]) {
                callerStackSymbol = [callerStackSymbolDetailsArr objectAtIndex:callerStackSymbolIndex];
                callerStackSymbol = [callerStackSymbol stringByReplacingOccurrencesOfString:@"]" withString:@""];
            }
        }
    }

    return callerStackSymbol;
}

6

রেফারেন্সের জন্য @ ইন্ট্রোপড্রোর উত্তরের সুইফট ২.০ সংস্করণ;

let sourceString: String = NSThread.callStackSymbols()[1]

let separatorSet :NSCharacterSet = NSCharacterSet(charactersInString: " -[]+?.,")
let array = NSMutableArray(array: sourceString.componentsSeparatedByCharactersInSet(separatorSet))
array.removeObject("")

print("Stack: \(array[0])")
print("Framework:\(array[1])")
print("Memory Address:\(array[2])")
print("Class Caller:\(array[3])")
print("Method Caller:\(array[4])")

5

এটি যদি ডিবাগিংয়ের জন্য হয় তবে একটি রাখার অভ্যাসটি পান NSLog(@"%s", __FUNCTION__);

আপনার ক্লাসে প্রতিটি পদ্ধতির ভিতরে প্রথম লাইন হিসাবে As তারপরে আপনি সর্বদা ডিবাগারের দিকে তাকানো থেকে পদ্ধতি কলের ক্রম জানতে পারবেন।


কোনওভাবে কোডটি সঠিকভাবে উপস্থিত হচ্ছে না। ফিউশনের আগে এবং পরে দুটি আন্ডারস্কোর রয়েছে
জিওভান্নি

আপনার কোডটি বন্ধ করতে ব্যাকটিক পলায়ন (`) ব্যবহার করে চেষ্টা করুন যাতে এটি সঠিকভাবে প্রদর্শিত হয়
howanghk

4
অথবা আরও ভাল __PRETTY_FUNCTION__ ব্যবহার করুন যা উদ্দেশ্য-সি সমর্থন করে এবং পদ্ধতির পাশাপাশি অবজেক্টের নাম প্রদর্শন করে।
প্রোনবার্ড

4

আপনি selfফাংশনে আর্গুমেন্টগুলির মধ্যে একটি হিসাবে পাস করতে পারেন এবং তারপরে ভিতরে কলার অবজেক্টের শ্রেণীবদ্ধ নাম পেতে পারেন:

+(void)log:(NSString*)data from:(id)sender{
    NSLog(@"[%@]: %@", NSStringFromClass([sender class]), data);
}

//...

-(void)myFunc{
    [LoggerClassName log:@"myFunc called" from:self];
}

এইভাবে আপনি যে কোনও বস্তু এটি পাস করতে পারেন যা আপনাকে সমস্যাটি কোথায় হতে পারে তা নির্ধারণ করতে সহায়তা করবে।


3

@ রয় ক্রোনেনফিল্ডের দুর্দান্ত উত্তরের একটি সামান্য অনুকূলিত সংস্করণ:

- (NSString *)findCallerMethod
{
    NSString *callerStackSymbol = nil;

    NSArray<NSString *> *callStackSymbols = [NSThread callStackSymbols];

    if (callStackSymbols.count >= 2)
    {
        callerStackSymbol = [callStackSymbols objectAtIndex:2];
        if (callerStackSymbol)
        {
            // Stack: 2   TerribleApp 0x000000010e450b1e -[TALocalDataManager startUp] + 46
            NSInteger idxDash = [callerStackSymbol rangeOfString:@"-" options:kNilOptions].location;
            NSInteger idxPlus = [callerStackSymbol rangeOfString:@"+" options:NSBackwardsSearch].location;

            if (idxDash != NSNotFound && idxPlus != NSNotFound)
            {
                NSRange range = NSMakeRange(idxDash, (idxPlus - idxDash - 1)); // -1 to remove the trailing space.
                callerStackSymbol = [callerStackSymbol substringWithRange:range];

                return callerStackSymbol;
            }
        }
    }

    return (callerStackSymbol) ?: @"Caller not found! :(";
}

2

@ এন্নুয়াইকিলার

//Add this private instance method to the class you want to trace from
-(void)trace
{
  //Go back 2 frames to account for calling this helper method
  //If not using a helper method use 1
  NSArray* stack = [NSThread callStackSymbols];
  if (stack.count > 2)
    NSLog(@"Caller: %@", [stack objectAtIndex:2]);
}

//Add this line to the method you want to trace from
[self trace];

আউটপুট উইন্ডোতে আপনি নীচের মতো কিছু দেখতে পাবেন।

কলার: 2 মাই অ্যাপ 0x0004e8ae - [আইআইএন ক্লাসরুমআইনিট বিল্ডমেনু] + 86

স্ট্যাক ফ্রেম সম্পর্কে আরও ডেটা আহরণের জন্য আপনি এই স্ট্রিংটিকে বিশ্লেষণ করতে পারেন।

2 = Thread id
My App = Your app name
0x0004e8ae = Memory address of caller
-[IINClassroomInit buildMenu] = Class and method name of caller
+86 = Number of bytes from the entry point of the caller that your method was called

এটি আইওএসে সনাক্তকরণ কলিং পদ্ধতি থেকে নেওয়া হয়েছিল ।


2

অনুলিপি এবং পেস্ট করার জন্য @ জিফ এইচ উত্তরের সুইফট 4 সংস্করণ ;]

let sourceString: String = Thread.callStackSymbols[1]
let separatorSet :CharacterSet = CharacterSet(charactersIn: " -[]+?.,")
var array = Array(sourceString.components(separatedBy: separatorSet))
array = array.filter { $0 != "" }

print("Stack: \(array[0])")
print("Framework:\(array[1])")
print("Memory Address:\(array[2])")
print("Class Caller:\(array[3])")
print("Method Caller:\(array[4])")

0

রেফারেন্সের জন্য @ জিফ এইচ উত্তরের সুইফট 3 সংস্করণ:

let sourceString: String = Thread.callStackSymbols[1]
let separatorSet: CharacterSet = CharacterSet(charactersIn: " -[]+?.,")
let array = NSMutableArray(array: sourceString.components(separatedBy: separatorSet))
array.remove("")

print("Stack: \(array[0])")
print("Framework:\(array[1])")
print("Memory Address:\(array[2])")
print("Class Caller:\(array[3])")
print("Method Caller:\(array[4])")
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.