I'm facing a complicated merge of two branches in my iOS app's version control. After I've gone through identifying and picking the conflicting lines in project.pbxproj, Xcode won't load the file. Running it through plutil shows this:
CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon in dictionary.
I've reverted and attempted the merge (carefully) a couple of times, and each time get the same results although I can't see where I'm introducing a format problem.
Is there a tool I can use to find out at least which line or object the error is in so that I can find the mistake I'm making?
I created the following test:
#import <Foundation/Foundation.h>
#import <err.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSString *path = [[NSFileManager defaultManager] stringWithFileSystemRepresentation:argv[1] length:strlen(argv[1])];
NSData *data = [NSData dataWithContentsOfFile:path];
if (!data)
errx(EXIT_FAILURE, "open failed: %s\n", argv[1]);
NSString *errorString;
id plist = [NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:NULL
errorDescription:&errorString];
if (!plist)
errx(EXIT_FAILURE, "%s\n", [errorString UTF8String]);
printf("plist successfully read\n");
}
return 0;
}
and ran it with a modified project.pbxproj:
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
x = 1
};
...
and got the following error:
2012-05-11 20:51:14.381 plist-test[41890:303] CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon in dictionary on line 6. Parsing will be abandoned. Break on _CFPropertyListMissingSemicolon to debug.
I'm sure you already considered this, but the only option I see is writing a quick utility.
You could try CFPropertyListIsValid() and hope it spits out something useful. The header says:
The debugging library version spits out some messages to be helpful.
Maybe this function could give you a bit more insight in its logging activity? I don't know what Apple considers "helpful" or what "some" means (maybe just, "Nope. It's invalid." along with returning false), but that'd be my next try.
Additionally, CFPropertyListCreateWithStream() may be helpful if you read a bit at a time. You could use it to zero in on the location of the error by feeding it in parts until it returns NULL. Cutting down the size when NULL is encountered would get you ever closer to its point of indigestion.
Related
Strange and funny think is going on
Code:
-(void)saveFile
{
NSFileManager *fileMng = [NSFileManager defaultManager];
if(![fileMng fileExistsAtPath:self.appFilesPath])
{
NSError *error = nil;
BOOL success = [fileMng createDirectoryAtPath:self.appFilesPath withIntermediateDirectories:YES attributes:nil error:&error];
if(!success)
{
NSLog([error localizedDescription]);
}
}
NSLog([NSString stringWithFormat:#"%#",self.appFilesPath]);
[fileMng createFileAtPath:self.fileFullPath contents:self.fileData attributes:nil];
[self.fileData writeToFile:self.fileFullPath atomically:YES];
}
and this line
NSLog([NSString stringWithFormat:#"%#",self.appFilesPath]);
should give me something like this
file://localhost/Users/user/Library/Application%20Support/iPhone%20Simulator/5.0/Applications/BF35B859-514B-45AA-8E3A-B2CE65BD82B6/Documents/AppFiles
Directory AppFiles should be created under ../Documents/ directory,
but it's not there...
and the nslog gives me something like this:
file://localhost/Users/user/Library/Application瑳楲杮楗桴潆浲瑡:敲敬獡e摡䕤瑮楲獥牆浯楄瑣潩慮祲:扯敪瑣潆䭲祥:汣獡s獩楋摮晏汃獡㩳氀湥瑧h畡潴敲敬獡e敳佴橢捥㩴潦䭲祥:敲潭敶扏敪瑣潆䭲祥:湩整敧噲污敵戀潯噬污敵爀浥癯䅥汬扏敪瑣s湩瑩猀慨敲䥤獮慴据e敲楧瑳牥敎睴牯䑫晥畡瑬䙳牯灁䥰㩄挀灯y摡佤橢捥㩴洀楡䉮湵汤e畢摮敬摉湥楴楦牥椀䕳畱污潔瑓楲杮:桳牡摥潃普杩牵瑡潩n潣湵牴䑹晥畡瑬潆..few more screens of this bush..帴㽻椽絩8筞㴿楩}ㅶ䀶㨰帴㽻椽絩椸㈱䀀䜢佅楐數偬楯瑮"㽻搽絤䀸㨰4㉶䀴㨰笴㴿摤㡽䀀倢剂煥敵瑳牥"ㅶ䀶㨰⌴匸㈱䀀㰢䕇协灵潰瑲摥楔敬敓獴敓癲牥牐硯䑹汥来瑡㹥"㍶䀶㨰笴㴿摤㡽㉤椴㈳瘀㘱㐺㡀ㅩ2㉶䀸㨰帴㽻搽絤䤸㈱ㅤ椶㐲瘀㈱㐺癞8ㅀ䀶㨰帴㡶ㅣ2筞硟捰损湯敮瑣潩彮㵳}ㅀ䀶㨰䀴常彻䍟剆湵潌灯紽㈱帀彻䍟剆湵潌灯紽䀸㨰4筞彟䙃畒䱮潯㵰}癞䀸㨰4ㅀ䀲㨰帴㡶瘀〲㐺㡀ㅀ䤲㘱䀀㰢华慃档䑥汥来瑡㹥"㉀䀸㨰䀴笸㴿摤ㅽ2㽻搽絤㠲㐺㽻搽絤常㉤4㽻∽慬楴畴敤搢氢湯楧畴敤搢}upport/iPhone 貌Š߈imulator/5.0/Applications/CAF90A92-5B85-4FC0-8482-3702C3E98F8D/Documents/AppFiles
when i run code second time, the if condision is skiped, but ../Documents/ directory is stil empty
来瑡㹥"㉀䀸 - i mean wtf, first time something like this,
restarting xcode, mac did't help,
simulator is all set to english,
it also happen in other projects,
keyboard setting ant nationalization looks ok,
so realy I have no clue what is wrong
any ideas?
You can not just NSLog a string. The string argument it takes is a format (like in printf) which interpeted specially. In your case, it is reading random memory because %20S means to interpret the next argument as pointer to null-terminated string of wide characters and print it right-aligned in 20 columns; and they are Chinese because most of Unicode is occupied by Chinese hieroglyphs.
This is the correct way to do it:
NSLog(#"%#", self.appFilesPath);
I am trying to understand how to set a label to be the text from an array when you press the button. When I press the button, the label disappears, and then nothing comes up. No crashes in code.
Relevant code:
-(void)setupArray {
wordArray = [[NSMutableArray alloc] init];
[wordArray addObject:#"test1"];
[wordArray addObject:#"test2"];
[wordArray addObject:#"test3"];
}
- (IBAction)start:(id)sender {
int value = (arc4random() % 3) + 1;
self.typeThis.text = [self.wordArray objectAtIndex:value];
}
typeThis is the label name, and I think I have hooked up everything already, i.e. set up the buttons/delegates/etc...I don't understand why it isn't working. Can anybody help?
considering you have bound everything properly and you are not under ARC. Here is a thing that might cause you the issue.
when you are allocating wordArray you can try using following code snippet.
NSMutableArray tempArray = [[NSMutableArray alloc] init];
self.wordArray = tempArray;
[tempArray release];
if you are under ARC you can try self.wordArray = [NSMutableArray array];
then add objects to self.wordArray i.e.[self.wordArray addObject:#"test1"];. Here is some explanation about arc4random().
EDIT :
Here's a public spec for Automatic Reference Counting and a quote from the public iOS 5 page:
Automatic Reference Counting (ARC) for Objective-C makes memory
management the job of the compiler. By enabling ARC with the new Apple
LLVM compiler, you will never need to type retain or release again,
dramatically simplifying the development process, while reducing
crashes and memory leaks. The compiler has a complete understanding of
your objects, and releases each object the instant it is no longer
used, so apps run as fast as ever, with predictable, smooth
performance.
It is possible to detect if ARC is enabled. Simply add the following snippet to any file that requires ARC.
#ifndef __has_feature
#define __has_feature(x) 0 /* for non-clang compilers */
#endif
#if !__has_feature(objc_arc)
#error ARC must be enabled!
#endif
More info :
http://clang.llvm.org/docs/LanguageExtensions.html#__has_feature_extension
HTH.
Your '+1' is giving you a result between 1 and 3, and your indexes are from 0 to 2, so I'd expect it to go wrong one time in 3.
Is this under ARC? If so, is wordArray declare as strong?
In my iOS project, I use one 3rd-party library, which is is incredible spamming into the console output. Can I apply any filtering to debug output.
If the library is using NSLog you can redefine it and discard the log message when it comes from the library. Example code:
#define NSLog(args...) [[Logger singleton] debugWithLevel:kDebug line:__LINE__ funcName:__PRETTY_FUNCTION__ message:args];
// poor man's nslog
#interface Logger : NSObject
typedef enum {
kTrace=0, kDebug=1, kInfo=2, kWarn=3, kError=4, KSilent=5
} LoggerLevel;
// ...
#implementation Logger
+(Logger *)singleton {
static dispatch_once_t pred;
static Logger *shared = nil;
dispatch_once(&pred, ^{
shared = [[Logger alloc] init];
shared.logThreshold = kTrace;
});
return shared;
}
-(void) debugWithLevel:(LoggerLevel)level
line:(int)line
funcName:(const char *)funcName
message:(NSString *)msg, ... {
va_list ap;
va_start (ap, msg);
msg = [[[NSString alloc] initWithFormat:msg arguments:ap] autorelease];
va_end (ap);
msg = [NSString stringWithFormat:#"%s %50s:%3d - %#", levelName[level], funcName, line, msg];
// ... filter by class name ...
fprintf(stdout,"%s\n", [msg UTF8String]);
}
#end
Note that funcName contains the classname and method sending the message. If the library is a good citizen and has classes that start with a prefix, discard the output if the className starts with that. Otherwise you have to load a list of classes from that library and check them before the fprintf line.
This of course, doesn't duplicate the log to syslogd like NSLog does, but who cares. :P
Works in Xcode 5.0 through 7.3, Apple no longer supports Xcode plug-ins as of Xcode 8.0.
MCLog should be what you're looking for.
This is an XCode plugin.
It depends if you're using directly the 3rd party library source code in your project or a binary library.
If you're using the source code I'd suggest to check what they are using to log the messages. It may have a way to reduce the verbosity. If they are using plain NSLog the only option would be to redefine NSLog in order to do some filtering, as Jano proposed you.
If they are using low level functions like printf and the like, your best option is to replace them with your own custom logging macro, like:
#ifdef DEBUG_3P
#define LOG_3P(str) NSLog(#"%s", str)
#else
#define LOG_3P(str) /* nothing */
#endif
Then, replace printf("a c string message") with LOG_3P("a c string message"). You'll need to customize the solution, adjust macro parameters or even add several macros for your case. And make a few search and replace until it works.
When you want to see the 3rd party library logs, just define DEBUG_3P in your build settings as C flags: -D DEBUG_3P, otherwise it will be mute.
If you're using a binary library you can just build it with its release configuration, disabling or reducing the logs verbosity to its minimum.
For Swift, I wrote a wrapper around print() that does just this. See here: https://github.com/SebastianMecklenburg/TagLog
It works by adding tags to debug messages and then filter the output by those tags. It works all in code and doesn't need an Xcode plugin.
After installing Xcode 3.2.5 iOS 4.2 an app that was perfectly working stopped working. I have seen that this has happened to others but cant understand how to solve it.
My questions are:
1. How can I know where it is crashing?
2. What can I do to better debug and pinpoint the problem.
Here is the call stack.
Tommy thanks for the answer. I have build and run and suggested but when it crashes it does not shows where it crashed. Also I added a breakpoint inside the method but it does not stops there. Any further ideas? Here is the code snippet.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
ApplicationData *appdata = [ApplicationData sharedInstance];
if(appdata.currentCategoryIndex >= 0) {
Category *category = [appdata.categoryList objectAtIndex:appdata.currentCategoryIndex];
if(category.records) {
[lab_norecords setHidden:YES];
} else {
[lab_norecords setHidden:NO];
return 0;
}
return [category.records count];
}
return 0;
}
Now I am getting this error:
I believe the source of the problem is here in the same subCategoryView:
- (id)init {
if([[NSBundle mainBundle] loadNibNamed:#"SubCategoryView" owner:self options:nil]) {
//if(self = [super initWit])
cellowner = [[TableCellOwner alloc] init];
[listTableView setBackgroundColor:[UIColor clearColor]];
[listTableView setSeparatorColor:[UIColor whiteColor]];
[listTableView initialize];
}
return self;
}
From the trace you've got, check out the second column. The most recent thing in your application was a call to SubCategoryView numberOfSectionsInTableView:, in the fourth row (the one numbered '3'). The triggered exception was NSRangeException, where you attempted to retrieved object 4294967295 from an array with 22 objects in it. 4294967295 is how -1 looks if you cast a signed 32bit number to an unsigned number, so for some reason you're doing something like:
NSInteger variable = -1;
[array objectAtIndex:variable];
Somewhere within SubCategoryView's numberOfSectionsInTableView. Best immediate guess: some change between 4.1 and 4.2 is causing whatever method you use to populate the table to come up with the wrong results.
To advance from here, make sure you're doing a debug build and launch with command+y (or go to Build, Build and Run - Breakpoints On). When your program crashes this time the debugging window should appear, showing you exactly the line your program throws an exception at and allowing you to inspect the state of all your program variables at that point. The debugger will also allow you to place breakpoints, step through your program one line at a time and all the other usual things.
Xcode's debugger console makes it easy to see any debugging messages my app sends out using NSLog(), but it always sticks a timestamp prefix on them:
2009-08-30 04:54:48.128 MyApp[94652:a0f] some log message
2009-08-30 04:54:50.647 MyApp[94652:a0f] another log message
...
I have no use for this prefix, and it takes up a lot of room. I have a feeling it is hard-coded into Apple's logging system, but just in case there is a solution out there:
Can I have the debugger console show me log messages without the timestamp prefix?
Something like this would be perfect:
some log message
another log message
...
NSLog() is what is doing that, not the debugger console.
The easiest way to avoid it is to not use NSLog at all. You could use fprintf(), but that is a pain in that it doesn't support %# format types.
I generally write a function for this:
void MyLog(NSString *format, ...) {
va_list args;
va_start(args, format);
NSString *formattedString = [[NSString alloc] initWithFormat: format
arguments: args];
va_end(args);
[[NSFileHandle fileHandleWithStandardOutput]
writeData: [formattedString dataUsingEncoding: NSNEXTSTEPStringEncoding]];
}
Obviously, modify it to add a newline or use a shorter prefix, etc...
(Fixed the stray ctrl-b)
Define a macro
#if __has_feature(objc_arc)
#define MDLog(format, ...) CFShow((__bridge CFStringRef)[NSString stringWithFormat:format, ## __VA_ARGS__]);
#else
#define MDLog(format, ...) CFShow([NSString stringWithFormat:format, ## __VA_ARGS__]);
#endif
And use this macro in you code like
NSLog(#"some log message");
MDLog(#"some log message");
Here is the output of console
NSLog->2014-01-28 10:43:17.873 TestApp[452:60b] some log message
MDLog -> some log message
P.S.
If anyone wants Custom Logs which gives you more info like method name / line number etc. can download the open source MLog.h on GitHub.
put in this one line code in your .pch file and you are done
#define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
notice the ## part
A way to keep using NSLog in conjunction with bbum's answer is to use a preprocessor macro to redefine NSLog to your own function
#define USECUSTOMLOGS 1
#if USECUSTOMLOGS
#define NSLog MyLog
#endif
This will replace NSLog with MyLog on compile time. Basically you can keep using NSLog everywhere and it will still use your custom format for the console window. You can also change it back to use NSLog at anytime by changing the 1 to a 0.
ARC Version:
void NFLog(NSString *format, ...)
{
va_list args;
va_start(args, format);
NSString *formattedString = [NSString stringWithFormat:format, args];
formattedString = [formattedString stringByAppendingString:#"\n"];
va_end(args);
[[NSFileHandle fileHandleWithStandardOutput] writeData: [formattedString dataUsingEncoding: NSUTF8StringEncoding]];
}
update:
What I am doing is add this code to xxx-Prefix.pch then you can use it anywhere:
#define newLine do { [(NSFileHandle*)[NSFileHandle fileHandleWithStandardOutput] writeData:[#"\n" dataUsingEncoding: NSUTF8StringEncoding]]; } while(0);
#define NFLog(args,...) do { [(NSFileHandle*)[NSFileHandle fileHandleWithStandardOutput] writeData:[[NSString stringWithFormat:args, ##__VA_ARGS__] dataUsingEncoding: NSUTF8StringEncoding]]; } while(0); newLine
and if you want NSLog back:
#define NFLog(args,...) NSLog(args,##__VA_ARGS__)
In the top left corner of the console window there is a pulldown menu that says All Output / Debugger Output / Target Output.
Select Target Output. It worked on my older versions of Xcode, but to be honest with you it doesn't with my current 4.3 version.
I hope this helps you.
JR
This is way more easier than the suggested solutions. Using carelesslyChoosy's solution and adding a little bit more to make it log entries on release builds only you get the macro below. Just add this macro to your header or .pch file. This macro will show log entries when the DEBUG flag is enabled, on release builds you won't see log entries.
#ifdef DEBUG
#define NSLog(FORMAT, ...) printf("%s\n", [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#define Log(x, ...) NSLog(#"%s %d: " x, __FUNCTION__, __LINE__, ##__VA_ARGS__)
#else
#define Log(x, ...)
#endif
Clean Log Macro
Here is a macro I've made for this purpose. It works exactly like NSLog but with just your text, no extra info
Macro (paste to your .h)
#define CLog(__string, ...) fprintf(stderr, "\n%s", [([NSString stringWithFormat:__string, ##__VA_ARGS__]) UTF8String])
Example use:
CLog(#"I am %i days and %i years old", 3, 7);
Logs:
I am 3 days and 7 years old