I'm getting a semantic warning on Xcode 4 :
*Declaration of 'struct sockaddr_in' will not be visible outside of this function*
the struct seems to be declared in netinet/in.h
The warning is getting marked on Reachability.h, its a class that I downloaded from Apple examples.
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
typedef enum {
NotReachable = 0,
ReachableViaWiFi,
ReachableViaWWAN
} NetworkStatus;
#define kReachabilityChangedNotification #"kNetworkReachabilityChangedNotification"
#interface Reachability: NSObject
{
BOOL localWiFiRef;
SCNetworkReachabilityRef reachabilityRef;
}
//reachabilityWithHostName- Use to check the reachability of a particular host name.
+ (Reachability*) reachabilityWithHostName: (NSString*) hostName;
//reachabilityWithAddress- Use to check the reachability of a particular IP address.
+ (Reachability*) reachabilityWithAddress: (const struct sockaddr_in*) hostAddress;
//reachabilityForInternetConnection- checks whether the default route is available.
// Should be used by applications that do not connect to a particular host
+ (Reachability*) reachabilityForInternetConnection;
//reachabilityForLocalWiFi- checks whether a local wifi connection is available.
+ (Reachability*) reachabilityForLocalWiFi;
//Start listening for reachability notifications on the current run loop
- (BOOL) startNotifier;
- (void) stopNotifier;
- (NetworkStatus) currentReachabilityStatus;
//WWAN may be available, but not active until a connection has been established.
//WiFi may require a connection for VPN on Demand.
- (BOOL) connectionRequired;
#end
I don't understand the warning, can someone explain it to me?
Thank you.
Someone filed a bug report against the behavior and got a response from someone here. Essentially, the problem is that you're declaring a new struct (so far as the compiler can tell) in the parameter of the method, so it will not be accessible elsewhere.
There is a quick fix for it. Simply add the following line to Reachability.h:
#import <netinet/in.h>
You're declaring a new struct in a method parameter, as opposed to at file scope.
The warning will go away if you add a forward declaration at the beginning of the file (somewhere before the #interface section).
struct sockaddr_in ;
Doing this instead of #import <netinet/in.h> avoids header file bloat.
(Speaking of reducing header bloat you can cut down header use in Reachability.h by replacing the lines
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
with
#import <SystemConfiguration/SCNetworkReachability.h>
)
Add #import in Reachability.h to get away with this
Related
I've created a UIViewController class with a XIB Attached. Without adding anything, the compiler tells me "UNEXEPTED # IN PROGRAM" on the .h file at the #interface line and repeat the same error on the #end line
#import <UIKit/UIKit.h>
#interface iPegasoDatiCorpoCli : UIViewController
-(id)initWithStrings:(NSString *)lblcorpo1 :(NSString *)lblcorpo2 :(NSString *)lblcorpo3 :(NSString *)<nibNameOrNil :(NSBundle *)nibBundleOrNil;
#end
This class is implemented to create a custo cell view and it worked till now. I've created also a new class just like this one but never used it and still gaves me the same error 3 Builds every 5. It's giving me headache
There is typo, extra > symbol in please check:
-(id)initWithStrings:(NSString *)lblcorpo1 :(NSString *)lblcorpo2 :(NSString *)lblcorpo3 :(NSString *)<nibNameOrNil :(NSBundle *)nibBundleOrNil;
----- ^
EDIT:
Why you are passing 6-7 arguments to a method. Wrap them in a class or pass an array of strings.
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.
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.
I have the following method in a NSDictionary category, to do a deep copy, which works fine.
I just upgraded from Xcode 4.1 to 4.2, and the Analyze function gives two analyzer warnings for this code, as indicated:
- (id)deepCopy;
{
id dict = [[NSMutableDictionary alloc] init];
id copy;
for (id key in self)
{
id object = [self objectForKey:key];
if ([object respondsToSelector:#selector(deepCopy)])
copy = [object deepCopy];
else
copy = [object copy];
[dict setObject:copy forKey:key];
// Both -deepCopy and -copy retain the object, and so does -setObject:forKey:, so need to -release:
[copy release]; // Xcode 4.2's Analyze says this is an incorrect decrement of the reference count?!
}
return dict; // Xcode 4.2's Analyze says this is a potential leak
}
Are these bugs in Xcode's analyzer, or are there changes I can make to avoid these warnings?
I'm not using ARC yet, though I am interested if there are additional changes needed to support ARC for this method.
Presumably, it is because deepCopy does not begin with the prefix copy.
So you may want to change to something like copyWithDeepCopiedValues (or something like that), and then see if the analyzer flags that.
Update
As Alexsander noted, you can use attributes to denote reference counting intent. This should (IMO) be the exception to the rule, and used rarely, if ever. Personally, I will not use attributes for objc methods because it is fragile.
The only attribute I have used so far has been consume, and every time I use these attributes has been in statically typed contexts (e.g. C functions and C++ functions and methods).
The reasons you should avoid attributes when possible:
1) Stick with conventions for the programmers' sake. The code is clearer and you do not need to refer to the documentation.
2) The approach is fragile. You can still introduce reference count imbalances, and attributes can be used to introduce build errors due to conflicts in attributes.
The following cases are all built with ARC enabled:
Case #1
#import <Foundation/Foundation.h>
#interface MONType : NSObject
- (NSString *)string __attribute__((objc_method_family(copy)));
#end
#implementation MONType
- (NSString *)string
{
NSMutableString * ret = [NSMutableString new];
[ret appendString:#"MONType"];
return ret;
}
#end
int main (int argc, const char * argv[])
{
#autoreleasepool {
id obj = nil;
if (random() % 2U) {
obj = [[NSAttributedString alloc] initWithString:#"NSAttributedString"];
}
else {
obj = [MONType new];
}
NSLog(#"Result: %#, %#", obj, [obj string]);
}
/* this tool's name is ARC, dump the leaks: */
system("leaks ARC");
return 0;
}
This program produces the following error: error: multiple methods named 'string' found with mismatched result, parameter type or attributes.
Great, the compiler's doing what it can to prevent these issues. What that means is that conflicts in attributes can introduce errors based on the translation. This is bad because when nontrivial codebases are combined and attributes conflict, you will have errors to correct and programs to update. This also means that simply including other libraries in translation units can break existing programs when attributes are used.
Case #2
Header.h
extern id NewObject(void);
Header.m
#import <Foundation/Foundation.h>
#import "Header.h"
#interface MONType : NSObject
- (NSString *)string __attribute__((objc_method_family(copy)));
#end
#implementation MONType
- (NSString *)string
{
NSMutableString * ret = [NSMutableString new];
[ret appendString:#"-[MONType string]"];
return ret;
}
#end
id NewObject(void) {
id obj = nil;
if (random() % 2U) {
obj = [[NSAttributedString alloc] initWithString:#"NSAttributedString"];
}
else {
obj = [MONType new];
}
return obj;
}
main.m
#import <Foundation/Foundation.h>
#import "Header.h"
int main (int argc, const char * argv[])
{
#autoreleasepool {
for (size_t idx = 0; idx < 8; ++idx) {
id obj = NewObject();
NSLog(#"Result: %#, %#", obj, [obj string]);
}
}
/* this tool's name is ARC, dump the leaks: */
system("leaks ARC");
return 0;
}
Ok. This is just bad. We've introduced leaks because the necessary information was not available in the translation unit. Here's the leaks report:
leaks Report Version: 2.0
Process 7778: 1230 nodes malloced for 210 KB
Process 7778: 4 leaks for 192 total leaked bytes.
Leak: 0x1005001f0 size=64 zone: DefaultMallocZone_0x100003000 __NSCFString ObjC CoreFoundation mutable non-inline: "-[MONType string]"
Leak: 0x100500320 size=64 zone: DefaultMallocZone_0x100003000 __NSCFString ObjC CoreFoundation mutable non-inline: "-[MONType string]"
Leak: 0x100500230 size=32 zone: DefaultMallocZone_0x100003000 has-length-byte: "-[MONType string]"
Leak: 0x100500390 size=32 zone: DefaultMallocZone_0x100003000 has-length-byte: "-[MONType string]"
note: the count may differ because we used random()
This means that because MONType is not visible to main(), the compiler bound the ARC properties to methods which were visible to the current TU (that is, string from declarations in Foundation, all of which follow convention). As a result, the compiler got it wrong and we were able to introduce leaks into our program.
Case 3
Using a similar approach, I was also able to introduce negative reference count imbalances (premature releases, or a messaged zombie).
note: Code not provided because Case #2 already illustrates how one can accomplish a reference count imbalance.
Conclusion
You can avoid all these problems and improve readability and maintainability by sticking with convention, rather than using attributes.
Bringing the conversation back to non-ARC code: Using attributes makes manual memory management more difficult for programmers' readability, and for the tools which are there to help you (e.g. compiler, static analysis). If the program is suitably complex such that the tools can't detect such errors, then you should reconsider your design, because it will be equally complex for you or somebody else to debug these issues.
Adding onto #Justin's answer, you can tell the compiler that -deepCopy returns a retained object by appending the NS_RETURNS_RETAINED attribute to the method's declaration like so:
- (id) deepCopy NS_RETURNED_RETAINED;
Alternatively, you can use explicitly control the method's "family" using the objc_method_family attribute like so:
- (id) deepCopy __attribute__((objc_method_family(copy)));
If you do this, the compiler will know that this method is in the copy family and returns a copied value.
Ever since I've upgraded to Xcode 4. I've got this error and i can't seem to figure out whats wrong.
error: expected member name or ';' after declaration specifiers [1]
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#interface SixViewController : UIViewController <AVAudioPlayerDelegate> {
IBOutlet UIImageView *play;
AVAudioPlayer *theAudio;
float progress;
NSTimer *timer;
IBOutlet UIProgressView *progressView;
int mainInt;
IBAction *timeOut;
}
It highlights the error on ibaction line
thanks
IBAction is intended as a return value for methods:
- (IBAction)someMethod;
... to tell Interface Builder that it is available for target/action connections. It is not intended as a variable data type, although you can get away with it when IBAction is defined as void.
However, you should use the correct data type for this variable, e.g. id for generic objects or maybe NSTimeInterval depending on what you're actually trying to do here.