I am seeing the compiler warn that "Instance method -cacheKeyForURL not found" and "Instance method -defaultCachePathForKey not found", in the following code:
SDWebImageManager *manager = [SDWebImageManager sharedManager];
NSString *cacheKey = [manager cacheKeyForURL:[NSURL URLWithString:imageUrl]];
NSString *cachePath = [[manager imageCache] defaultCachePathForKey:cacheKey];
Yet clearly, these methods are defined. Here, for example, is the method definition in SDImageCache.h:
/**
* Get the default cache path for a certain key
*
* #param key the key (can be obtained from url using cacheKeyForURL)
*
* #return the default cache path
*/
- (NSString *)defaultCachePathForKey:(NSString *)key;
At the top of my code file, I am including the relevant files from the SDWebImage project:
#import <SDWebImage/UIImageView+WebCache.h>
#import <SDWebImage/SDImageCache.h>
#import <SDWebImage/SDWebImageManager.h>
Moreover, sharedImageManager is defined in SDWebImageManager.h and the compiler is having no problems finding it. I only have warnings on the 2nd and 3rd lines.
My code runs fine and these methods both work without crashing. Why is the compiler telling me it cannot find it?
I am running XCode 6, compiling for Active Architecture Only, iPhone 6 Simulator.
UPDATE
When I compile for Distribution, "All Architectures", suddenly it can find cacheKeyForURL and defaultCachePathForKey, no problem, but setImageWithURL is now deprecated?
I do see the deprecation warnings in UIImageView+WebCache.h, but I'm just super-confused why building for these different architectures is turning on/off various compiler warnings when the header files of SDWebImage don't seem to have anything architecture-specific to them.
I figured this out by more closely inspecting the error in the "Report Navigator" (neé Log Navigator).
It turns out that there were some very old SDWebImageManager.h files in the "Derived Data" folder that it was choosing to link against. Unclear why they did not go away upon a clean of my project. (Possibly connected to the fact that I migrated from submodules to including SDWebImage via Cocoapods?)
I used this answer on Stack Overflow to navigate to my DerivedData folder, and then I manually deleted the subfolder for my project. After doing that, the project now builds successfully without the spurious warnings.
Related
I'm going to create a mail plugin for the OS X Mail.app application for some additional features.
I have no idea where to start as there is no official documentation for plugins.
Can anyone please help me, how can I start the project.
Is there any initial link or tutorial, please suggest?
As noted, writing Apple Mail plugins is not straightforward, since it only has a private plugin API, which is entirely undocumented and can change with any new version of Mail.app. The best code example is GPGMail, which is open source & still active (already working on Yosemite support). Here is what I successfully did to get started (will put it up on github once finished):
How to build a minimal Apple Mail plugin (as of Mavericks & Xcode 6.0.1)
you need to create an OSX "Bundle" project in XCode
wrapper extension is mailbundle (under Packaging in the project Build settings)
a bundle needs to be stored under ~/Library/Mail/Bundles (as Build Phase add a Copy Files action with that as absolute path destination and the *.mailbundle from your build/ folder as item to copy)
for development, I have set up /Applications/Mail.app as executable in my run scheme, so that Run in XCode will build it, copy the bundle and start mail; note that at this point you'll get an error from Mail that your plugin cannot be started and was disabled
you need to provide a list of SupportedPluginCompatibilityUUIDs in the Info.plist, I stole it from GPGMail, these change with new Mail/OSX versions
use class-dump to generate the header files from Mail.app's private API
starting point is MVMailBundle, which you have to inherit from and which has a registerBundle method to hook you in
I extracted that from the huge generated header file in a small MVMailBundle.h header to include where needed (as done by GPGMail)
create a new class MyMailBundle, inheriting from NSObject
it needs an initialize method
and set it as "Principle class" in the Info.plist so that it gets run when the bundle is loaded by Mail.app
#import <Cocoa/Cocoa.h>
#interface MyMailBundle : NSObject
+ (void)initialize;
#end
initialize implementation: previously, you could use the simple way and directly inherit as done in Letterbox, however, since 64-bit runtimes of Objective-C you have to use the dynamic way as done by GPGMail:
using NSClassFromString to dynamically get the MVMailBundle class
and class_setSuperclass from <objc/runtime.h> to have your own class inherit from it
and then call registerBundle on it casted as MVMailBundle (requires include of MVMailBundle.h)
#import <objc/runtime.h>
#import "MVMailBundle.h"
#import "MyMailBundle.h"
#implementation MyMailBundle
+ (void)initialize
{
NSLog(#"Loading MyMail plugin...");
// since 64-bit objective-c runtimes, you apparently can't load
// symbols directly (i.e. through class inheritance) and have to
// resort to NSClassFromString
Class mvMailBundleClass = NSClassFromString(#"MVMailBundle");
// If this class is not available that means Mail.app
// doesn't allow plugins anymore or has changed the API
if (!mvMailBundleClass)
return;
// dynamically change super class hierarchy
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated"
class_setSuperclass([self class], mvMailBundleClass);
#pragma GCC diagnostic pop
// register our plugin bundle in mail
[[((MyMailBundle *)self) class] registerBundle];
NSLog(#"Done registering MyMail plugin.");
}
#end
add some NSLog logging calls to verify the right thing is happening, they'll be visible in XCode's console when running/debugging Mail.app from within XCode or alternatively in the system logs of Console.app
This should successfully run the plugin in Mail with no error!
The next steps involve crazy things like MethodSwizzling and ClassPosing to modify Mail's behavior, where GPGMail can be a helpful example. (Haven't been there myself yet)
For reference, here are some of the resources that helped me:
GPGMail
Adam Nash: Getting Ready to Write an Apple Mail.app Plug-in for Mac OS X - some good links, but apparently he never finished the project, so no code
James R. Eagan: Demystifying Mail.app Plugins on Leopard - using PyObjC to write a plugin in Python, explains the basic mechansims, very useful
Aaron Harnly: Mail Plugin Template - for XCode 2 I think, unfortunately the template (download a zip) doesn't work as template in Xcode anymore, but the code is still useful to look at
Aaron Harnly: Letterbox sources - from the same guy, but also from 2007, very outdated; contains a readme from the template, though it doesn't really help if you can't use the template.
There is no official supported way to build such a tool - you need to start trying to hook in to Mail.app without any official support.
If you want to persist on this sort of thing, then you'll need to understand how Mail.app internals work, which is a bunch of using the debugger and class dump to inspect libraries in other apps:
https://github.com/nygard/class-dump
You'll probably also want a way to inject code into other applications, for example:
https://github.com/rentzsch/mach_inject
And every time Apple update Mail.app you'll potentially need to redo everything :)
I keep getting this for situations that are patently false, related to objective-c categories.
NB: this was working fine, then stopped working overnight.
It's as if Xcode is fundamentally broken in it's ability to "read the file system", and it's driving me nuts. Any ideas on how to force it to ... read the file system ... would be appreciated.
e.g.:
Start Xcode, write a file, import it, using Xcode autocomplete.
cmd-click on the import line, and it jumps to the header file
A few builds later, Xcode flags a Warning:, e.g. "Class method '+stringFromCGPath:' not found (return type defaults to 'id')"
Now when you cmd-click on the import line, Xcode flashes up a dialog "Symbol not found" (world's worst dialog box? doesn't even have a confirm, it flashes and vanishes)
If you run the app, it crashes on that line, saying the selector not recognized
Then, to prove how FUBAR Xcode is:
Quit Xcode, restart
Cmd-click is working again
...but the Warning is still in place, and the app still crashes
After a few seconds, cmd-click stops working
NB: things I've checked:
The file is in the project folder? YES
The .m file is included in the Target? YES
The .m file is in the list of files to compile? YES
Do a CLEAN ... then a BUILD? YES
UPDATE: an example header I'm trying to import - that I have been successfully importing for months, and worked fine in hundreds of builds, and I have NOT changed (confirmed using SCM):
#import <Foundation/Foundation.h>
#import "CGGeometryExtensions.h"
#interface NSString(CGPath)
+(NSString*) NSStringFromCGPath:(CGPathRef) path;
#end
UPDATE2: actually, this doesn't crash at runtime - it was crashing because there was a typo in the call to "NSStringFromCGPath:" (one letter was lower case when it should have been upper case). But this was hard to see because of XCode's claim that the whole header file didn't exist - even though, as noted above, the IMPORT line was auto-generated by Xcode.
It sounds as though you may have problems with the indexer. Have you got multiple targets in your project, or multiple projects in a workspace? If so, make sure they all build completely cleanly - a failure indexing one target can mess up code completion on another.
You might also try deleting your project's DerivedData folder
I'm creating an iPhone 5.0 project in Xcode 4.2 and would like to find the code coverage when the unit tests are executed. I'm quite new to the Xcode environment, and I've followed the steps provided here. I'm able to modify the Build Settings for the test target correctly, and link the "libprofile_rt.dylib" file fine.
At this point, when I execute the tests (using Command-U), the code compiles and the tests pass. I do not encounter the problem described here. In addition, I've installed CoverStory.
The author in the first link mentions "Just run your unit tests and view the code coverage data as usual"; however, I cannot find .../Objects-normal/i386.
Just to get things working, I created a new project with the following class:
#import "SomeClass.h"
#implementation SomeClass
#synthesize someValue;
-(void)performWork:(BOOL)now withValue:(int)value {
if (now) {
someValue = value;
}
else {
someValue = value - 1;
}
}
#end
and test class:
#import "CodeCoverageTests.h"
#import "SomeClass.h"
#implementation CodeCoverageTests
- (void)testExample {
SomeClass *obj = [[SomeClass alloc] init];
[obj performWork:YES withValue:3];
STAssertEquals(obj.someValue, 3, #"Value was not 3");
}
#end
Ideally, I'd like to be notified in some way that when the tests execute, the else clause in the performWork method is never fired.
I thus have the following questions:
Is the root problem that there's no support for what I'm trying to do with the new compiler?
Is the only solution the one described by user chown in response to the question I linked above?
Will I be able to use CoverStory (or something similar) if I follow the solution from 2) ?
Update:
After some struggle, I was finally able to find the location of the "SomeClass.gcno" and "SomeClass.gcda" files (thanks #bjhomer - see this link), and they depicted beautifully that the if part of the conditional statement in performWork was covered (and the else was not). To make sure, I modified the test as follows:
- (void)testExample
{
SomeClass *obj = [[SomeClass alloc] init];
[obj performWork:NO withValue:3];
STAssertEquals(obj.someValue, 2, #"Value was not 2");
}
After re-building and re-execution of the unit test, I reloaded the .gcno and .gcda files. CoverStory showed that the coverage changed to the else part of the performWork method. There was one small caveat however:
I needed to modify the build settings of the <TargetName> (not the <TargetNameTest> as shown here) in order for the "SomeClass.gcno" and "SomeClass.gcda" files to be created in ...<TargetName>.build/Objects-normal/i386/ directory.
Thanks again for your help!
It sounds like your main problem is that you cannot find the Build/Intermediates/<SchemeName>.build/<ConfigurationName>-<PlatformName>/<TargetName>.build/Objects-normal/<ArchitectureName> directory. That directory is always used when building, whether or not you're doing code coverage. That's where all the intermediate files generated by the compiler are stored, and is also where the final .gcno and .gcda files should exist if you're doing code coverage. If you cannot find that directory, the problem is not related to coverage, the problem is that you need to find that directory.
To answer your questions.
Code coverage is supported in the LLVM Compiler, as of Xcode 4.2. It will not work with LLVM-GCC, so make sure you're not using that.
No, it is not necessary to hack in support for GCC 4.2 in Xcode 4.2. I'm running code coverage with Xcode 4.2 right now, having done none of the above.
You should be able to use CoverStory either way; hacking in support for GCC 4.2 would not change where the built products go.
Now I'm involved in a project which needs to download a huge amount of images from server. Following the recommendation online, I tried the ASIHttpRequest. But when I copied all the necessary classes into my project, I got 30+ errors in those classes. Most of the errors are about using retain, release or autorelease. Because I'm using Xcode 4.2.1, explicit retain, release and autorelease is forbidden. But some other errors are quite ridiculous.
for example, in class ASIDataCompressor.m, following method should return NSData
- (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish
but I see one portion of the method return NO
if (status == Z_STREAM_END) {
break;
} else if (status != Z_OK) {
if (err) {
*err = [[self class] deflateErrorWithCode:status];
}
return NO;
}
Some other classes also have similar problems.
My questions are:
Did I download the wrong package?
How to let compiler ignore those explicit retain, release and autorelease?
"Xcode 4.2.1, explicit retain, release and autorelease is forbidden" because you have ARC enabled when you created your project. Disable ARC.
ASIDataCompressor.m method looks fine here. Don't know how you got it wrong.
Since you just picked up ASIHTTP in your project I would recommend switching to AFNetworking because read this: [request release]
As stated above, when using ARC, you cannot use (and no longer need) retain/release/etc.
If you want your overall project to still have ARC, you can disable it for that one file.
When you migrate a project to use ARC, the -fobjc-arc compiler flag is set as the default for all Objective-C source files. You can disable ARC for a specific class using the -fno-objc-arc compiler flag for that class.
In Xcode, go to target Build Phases tab > open the Compile Sources group to reveal the source file list > double-click the file for which you want to set the flag > enter -fno-objc-arc in the pop-up panel, then click Done.
I am running cocos2d 1.0.1. I am getting Warning Errors regarding this code saying that the initWithFrame method is not found. I believe it is responsible for crashing my application, while logging "Unknown Error"
glView = [[EAGLView alloc] initWithFrame:[window bounds]
pixelFormat:kEAGLColorFormatRGBA8
depthFormat:GL_DEPTH_COMPONENT24_OES
preserveBackbuffer:NO];
This is the Build WARNING I got:
WARNING: No '-initWithFrame: pixelFormat:
depthFormat:preserveBackbuffer:' method found
Reading forum posts from a year ago, Riq recommended the above method posted, but that did not work.
I do have my EAGLView.h/m files, they are under the iOS subFolder of the Platforms subFolder.
I tried adding an #class EAGLView; declaration in the App.h file, but I still couldn't even get Xcode to jump to the definition of the EAGLView class. Moving the two EAGLView .h and .m files up to the main Cocos2d folder did nothing either.
My question is: how do I get these files to talk, because there's clearly a lack of communication.
The format of EAGLView initWith… methods have changed. In your case you simply need to add the remaining additional parameters as described in the link.