XCode 12.4 , lldb debug on one IOS app
using command 'expression'
(int) printf("hello world\n");
no output ,but
(void) NSLog(#"hello world\n");
it did work , why ? can I change to C/C++ mode ?
enter image description here
also, I find that
(void) NSLog(#"number = %i", 123);
result is "number = 307823584".
i don't know what it means. it seem that only objc object is allowed ?
SString* temp = #"yuv";
(void) NSLog(#"str = %#", temp);
output is "str = yuv" (corret)
but
(void) NSLog(#"str = %s", "123456");
output is "str = »¡#" (error)
Related
I am doing a lot of inserts in my sqlite db. For some reason, at a specific point, the app crashes. I checked the insert command - everything is fine.
If I run it on an iPhone 4 device - it runs perfectly.
The problem is that I don't get any error messages, not even memory warnings. xCode seems to still run, but on the device, the app crashes.
This is my code:
sqlite3_stmt *compiledStatement;
for (UpdateItems *one in arrList) {
NSString *stat;
stat = [[NSString alloc] initWithFormat:#"insert into table values (null, (select id from t1 where code='%#'), (select id from t2 where c='%#'), '%#', '%#', '%#', '%#', '%#', '%#')", one.bk, one.code, one.data, one.b, one.bV, one.s, one.sV, one.o];
if(sqlite3_prepare_v2(database, [stat UTF8String], -1, &compiledStatement, NULL) == SQLITE_OK)
{
while(YES){
NSInteger result = sqlite3_step(compiledStatement);
printf("db error: %s\n", sqlite3_errmsg(database));
if(result == SQLITE_DONE){
index = index + 1;
double totalPrc = 0.75f + roundf(((double) index / totalRecords) / (100 / 20) * 100.0f) / 100.0f;
if (self.percentageCompleted != totalPrc) {
self.percentageCompleted = totalPrc;
[self performSelectorOnMainThread:#selector(refreshHUD) withObject:nil waitUntilDone:NO];
}
break;
}
else if(result != SQLITE_BUSY){
printf("db error: %s\n", sqlite3_errmsg(database));
break;
}
}
sqlite3_reset(compiledStatement);
}
[stat release];
}
How can I track this, to see what is the problem?
You might not see anything on xcode console, what about device crash logs ? Whenever there is a crash, crash reporter generates a crash report. Use XCode organizer to bring up device logs, symbolicate them
If the App that crashed was built with: stripping debug symbols - NO:
a nice symbolicated crash log should appear in your organizer window giving a stack trace, etc:
NOTE: I'm developing for Mac, not iOS!
- (void)recordTransaction:(SKPaymentTransaction *)transaction
{
if ([transaction.payment.productIdentifier isEqualToString:kInAppProIdentifier])
{
[[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:#"proUpgradeTransactionReceipt" ];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
I get this error from the compiler:
error: property 'transactionReceipt' not found on object of type 'SKPaymentTransaction *'; did you mean 'transactionDate'? [3]
Also, I can't find the transactionReceipt property in the reference for the SKPaymentTransaction class! (Even though this page contains some references to "receipts", there's not a transactionReceipt property).
But the documentation says it is supposed to exist!
A successful transaction includes a transactionIdentifier property and a transactionReceipt property that record the details of the processed payment. Your application is not required to do anything with this information. You may wish to record this information to establish an audit trail for the transaction. If your application uses a server to deliver content, the receipt can be sent to your server and validated by the App Store.
What is wrong with this?
The property is private and returns an empty string on OS X.
As stated in Apple's docs here:
https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/StoreKitGuide/VerifyingStoreReceipts/VerifyingStoreReceipts.html#//apple_ref/doc/uid/TP40008267-CH104-SW1
"On iOS, this is the value of the transaction's transactionReceipt
property. On OS X, this is the entire contents of the receipt file
inside the application bundle. Encode the receipt data using base64
encoding."
To get the receipt, use:
[NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]]
An example of this working for both iOS and OS X to get the receipt and sending it to a server for verification (with a macro set for the OS X build):
NSData *tr ;
#ifdef OSX
tr = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]] ;
#else
tr = [transaction transactionReceipt];
#endif
NSString *jsonObjectString = [[self encode:(uint8_t *)[tr bytes] length:[tr length]] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSString *completeString = [NSString stringWithFormat:#"https://ssl.myserver.com/verify.php?%#", jsonObjectString];
NSURL *urlForValidation = [NSURL URLWithString:completeString];
NSMutableURLRequest *validationRequest = [[NSMutableURLRequest alloc] initWithURL:urlForValidation];
[validationRequest setHTTPMethod:#"GET"];
NSData *responseData = [NSURLConnection sendSynchronousRequest:validationRequest returningResponse:nil error:nil];
Be careful where verifying, the json object for OS X and iOS receipts are different so you'll likely need separate server side code for validation.
Update: Adding function to encode receipt for posting:
+ (NSString *)encode:(const uint8_t *)input length:(NSInteger)length {
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
NSMutableData *data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t *output = (uint8_t *)data.mutableBytes;
for (NSInteger i = 0; i < length; i += 3) {
NSInteger value = 0;
for (NSInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
NSInteger index = (i / 3) * 4;
output[index + 0] = table[(value >> 18) & 0x3F];
output[index + 1] = table[(value >> 12) & 0x3F];
output[index + 2] = (i + 1) < length ? table[(value >> 6) & 0x3F] : '=';
output[index + 3] = (i + 2) < length ? table[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}
I class-dumped StoreKit to find out if this method was present and it is. Here is the header:
#interface SKPaymentTransaction : NSObject
{
id _internal;
}
- (id)init;
- (id)initWithDictionary:(id)arg1;
- (id)initWithPayment:(id)arg1;
- (void)dealloc;
#property(readonly) NSError *error;
#property(readonly) SKPaymentTransaction *originalTransaction;
#property(readonly) SKPayment *payment;
#property(readonly) NSDate *transactionDate;
#property(readonly) NSString *transactionIdentifier;
- (id)transactionReceipt;
#property(readonly) long long transactionState;
- (BOOL)canMergeWithTransaction:(id)arg1;
- (id)matchingIdentifier;
- (BOOL)mergeWithTransaction:(id)arg1;
- (id)_transactionIdentifier;
#end
You can use this method with [transaction transactionReceipt] (and get a warning). Apple may or may not consider this use of a private method and reject your application; but, for testing purposes, it is there.
According to Apple's official 10.7 documentation of SKPaymentTransaction, there is no transactionReceipt property.
by default NSLog outputs a long string before the requested output,
e.g:
NSLog(#"Log message");
Outputs to the console:
2011-04-15 11:23:01.692 MyAppName[23160:903] Log message
I know I can add the filename and line number to the log, but how do I get rid of all the date, time and app name that appears before the message?
I find it really clutters the console in Xcode making it harder to find the information I'm after.
This is definitely the FIRST thing I do on a new project. NSLog(…) has diarrhea of the mouth. Here is a basic macro that lets you get some peace and quiet.. AND log basic objects without the annoying NSLog(#"%#", xYz); syntax (instead you just NSLog(xYz);).
#define NSLog(fmt...) NSShutUp(__PRETTY_FUNCTION__,fmt)
#define UTF8FMT(fmt,argL) \
[NSString.alloc initWithFormat:fmt arguments:argL].UTF8String
void NSShutUp(const char*func, id fmt, ...) {
if (![fmt isKindOfClass:NSString.class])
// it's not a string (aka. the formatter), so print it)
fprintf (stderr, "%s: %s\n", func,
[[NSString stringWithFormat:#"%#",fmt,nil]UTF8String]);
else { va_list argList; va_start (argList, fmt);
fprintf (stderr, "%s: %s\n", func, UTF8FMT(fmt,argList));
va_end (argList);
} }
/* SAMPLE RUN */
int main (void) { NSString *a; NSNumber *b; NSArray *c;
NSLog(a = #"Ahh, silence." );
NSLog(b = #(M_PI) );
NSLog(c = #[#"Arrays, baby!"] );
// Old syntax still works.
NSLog(#"%# * %# * %#",a,b,c);
return 0;
}
OUTPUT
int main(): Ahh, silence.
int main(): 3.141592653589793
int main(): (
"Arrays, baby!"
)
int main(): Ahh, silence. * 3.141592653589793 * (
"Arrays, baby!"
)
i would recommend that you start using a better alternatives to NSlog like SOSMAX or NSLogger.
Here is a bit overview of both of them
http://learning-ios.blogspot.com/2011/05/better-nslog-ing.html
I'm using an NSTask to grab the output from /usr/bin/man. I'm getting the output but without formatting (bold, underline). Something that should appear like this:
Bold text with underline
(note the italic text is actually underlined, there's just no formatting for it here)
Instead gets returned like this:
BBoolldd text with _u_n_d_e_r_l_i_n_e
I have a minimal test project at http://cl.ly/052u2z2i2R280T3r1K3c that you can download and run; note the window does nothing; the output gets logged to the Console.
I presume I need to somehow interpret the NSData object manually but I have no idea where to start on that. I'd ideally like to translate it to an NSAttributedString but the first order of business is actually eliminating the duplicates and underscores. Any thoughts?
What is your actual purpose? If you want to show a man page, one option is to convert it to HTML and render it with a Web view.
Parsing man’s output can be tricky because it is processed by groff using a terminal processor by default. This means that the output is tailored to be shown on terminal devices.
One alternative solution is to determine the actual location of the man page source file, e.g.
$ man -w bash
/usr/share/man/man1/bash.1.gz
and manually invoke groff on it with -a (ASCII approximation) and -c (disable colour output), e.g.
$ gunzip -c /usr/share/man/man1/bash.1.gz | groff -c -a -Tascii -man
This will result in an ASCII file without most of the formatting. To generate HTML output,
$ gunzip -c /usr/share/man/man1/bash.1.gz | groff -Thtml -man
You can also specify these options in a custom configuration file for man, e.g. parseman.conf, and tell man to use that configuration file with the -C option instead of invoking man -w, gunzip, and groff. The default configuration file is /private/etc/man.conf.
Also, you can probably tailor the output of the terminal device processor by passing appropriate options to grotty.
Okay, here's the start of my solution, though I would be interested in any additional (easier?) ways to do this.
The output returned from the Terminal is UTF-8 encoding, but the NSUTF8StringEncoding doesn't interpret the string properly. The reason is the way NSTask output is formatted.
The letter N is 0x4e in UTF-8. But the NSData corresponding to that is 0x4e 0x08 0x4e. 0x08 corresponds to a Backspace. So for a bold letter, Terminal prints letter-backspace-letter.
For an italic c, it's 0x63 in UTF-8. The NSData contains 0x5f 0x08 0x63, with 0x5f corresponding to an underscore. So for italics, Terminal prints underscore-backspace-letter.
I really don't see any way around this at this point besides just scanning the raw NSData for these sequences. I'll probably post the source to my parser here once I finish it, unless anybody has any existing code. As the common programming phrase goes, never write yourself what you can copy. :)
Follow-Up:
I've got a good, fast parser together for taking man output and replacing the bold/underlined output with bold/underlined formatting in an NSMutableAttributedString. Here's the code if anybody else needs to solve the same problem:
NSMutableIndexSet *boldChars = [[NSMutableIndexSet alloc] init];
NSMutableIndexSet *underlineChars = [[NSMutableIndexSet alloc] init];
char* bBytes = malloc(1);
bBytes[0] = (char)0x08;
NSData *bData = [NSData dataWithBytes:bBytes length:1];
free(bBytes); bBytes = nil;
NSRange testRange = NSMakeRange(1, [inputData length] - 1);
NSRange bRange = NSMakeRange(0, 0);
do {
bRange = [inputData rangeOfData:bData options:(NSDataSearchOptions)NULL range:testRange];
if (bRange.location == NSNotFound || bRange.location > [inputData length] - 2) break;
const char * buff = [inputData bytes];
if (buff[bRange.location - 1] == 0x5f) {
// it's an underline
//NSLog(#"Undr %c\n", buff[bRange.location + 1]);
[inputData replaceBytesInRange:NSMakeRange(bRange.location - 1, 2) withBytes:NULL length:0];
[underlineChars addIndex:bRange.location - 1];
testRange = NSMakeRange(bRange.location, [inputData length] - (bRange.location));
} else if (buff[bRange.location - 1] == buff[bRange.location + 1]) {
// It's a bold
//NSLog(#"Bold %c\n", buff[bRange.location + 1]);
[inputData replaceBytesInRange:NSMakeRange(bRange.location - 1, 2) withBytes:NULL length:0];
[boldChars addIndex:bRange.location - 1];
testRange = NSMakeRange(bRange.location, [inputData length] - (bRange.location));
} else {
testRange.location = bRange.location + 1;
testRange.length = [inputData length] - testRange.location;
}
} while (testRange.location <= [inputData length] - 3);
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString:[[NSString alloc] initWithData:inputData encoding:NSUTF8StringEncoding]];
NSFont *font = [NSFont fontWithDescriptor:[NSFontDescriptor fontDescriptorWithName:#"Menlo" size:12] size:12];
NSFont *boldFont = [[NSFontManager sharedFontManager] convertFont:font toHaveTrait:NSBoldFontMask];
[str addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, [str length])];
__block NSUInteger begin = [underlineChars firstIndex];
__block NSUInteger end = begin;
[underlineChars enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
if (idx - end < 2) {
// it's the next item to the previous one
end = idx;
} else {
// it's a split, so drop in the accumulated range and reset
[str addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSSingleUnderlineStyle] range:NSMakeRange(begin, (end-begin)+1)];
begin = idx;
end = begin;
}
if (idx == [underlineChars lastIndex]) {
[str addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInt:NSSingleUnderlineStyle] range:NSMakeRange(begin, (end-begin)+1)];
}
}];
begin = [boldChars firstIndex];
end = begin;
[boldChars enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
if (idx - end < 2) {
// it's the next item to the previous one
end = idx;
} else {
// it's a split, so drop in the accumulated range and reset
[str addAttribute:NSFontAttributeName value:boldFont range:NSMakeRange(begin, (end-begin)+1)];
begin = idx;
end = begin;
}
if (idx == [underlineChars lastIndex]) {
[str addAttribute:NSFontAttributeName value:boldFont range:NSMakeRange(begin, (end-begin)+1)];
}
}];
Another method would be to convert the man page to PostScript source code, run that through the PostScript-to-PDF converter, and put that into a PDFView.
The implementation would be similar to Bavarious's answer, just with different arguments to groff (-Tps instead of -Thtml).
This would be the slowest solution, but also probably the best for printing.
Well, I'm starting development on the Mac OS X this code that you'll see is in a book that I bought, really basic like Chapter 3. And I can't run it. PLEASE HELP ME:
C301.m :
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
if (argc == 1) {
NSLog (#"You need to provide a file name");
return -1;
}
FILE *wordFile = fopen("tmp/words.txt", "r");
char word[100];
while (fgets(word, 100, wordFile)) {
word[strlen(word) - 1] = '\0';
NSLog(#"%s is %d characters long", word, strlen(word));
}
fclose(wordFile);
return 0;
} //main
The file is in its place.
Thank you so much!
I am guessing wordFile is NULL (you should check for this); that you are mistaken: the file in fact does not exist, and finally that you really meant "/tmp/words.txt" instead of "tmp/words.txt"