Changed +Load Method Order in Xcode 7

Changed +load method order in Xcode 7

TL,DR: It's xctest's fault, not objc's.

This is because of how the xctest executable (the one that actually runs the unit tests, located at $XCODE_DIR/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/Xcode/Agents/xctest loads its bundle.

Pre-Xcode 7, it loaded all referenced test bundles before running any tests. This can be seen (for those that care), by disassembling the binary for Xcode 6.4, the relevant section can be seen for the symbol -[XCTestTool runTestFromBundle:].

In the Xcode 7 version of xctest, you can see that it delays loading of testing bundles until the actual test is run by XCTestSuite, in the actual XCTest framework, which can be seen in the symbol __XCTestMain, which is only invoked AFTER the test's host application is set-up.

Because the order of these being invoked internally changed, the way that your test's +load methods are invoked is different. There were no changes made to the objective-c-runtime's internals.

If you want to fix this in your application, you can do a few things. First, you could manually load your bundle using +[NSBundle bundleWithPath:], and invoking -load on that.

You could also link your test target back to your test host application (I hope you're using a separate test host than your main application!), which would make it be automatically loaded when xctest loads the host application.

I would not consider it a bug, it's just an implementation detail of XCTest.

Source: Just spend the last 3 days disassembling xctest for a completely unrelated reason.

XCode 7 XCTest(Kiwi) +load category methods called twice

It appears that you have included the same class extension in both the main application binary and in your test bundle. This would also explain why you see a separate setup of static dispatch_once tokens on the second load.

Why this is the case may be a number of things:

  • .mm-file is included in both targets
  • Xcode loads the test binary twice due to changes in test-procedure
  • Both test target and application link to the same .a file containing the +load method

Order of events when loading a View in iOS

Other than cases where the order of messages is clearly defined or strongly implied by names, you should avoid depending on any particular order. For example, you can reasonably expect -viewWillAppear to be called before -viewDidAppear for any given view, but don't expect one view's -viewWillAppear to be called in any particular order with respect to any message sent to a different view.

If you need help figuring out how to implement a particular feature without depending on order, please ask. But again, unless the order of invocation is documented or blatantly obvious from the method names, don't expect a particular order.

Update: I don't see exactly what's going wrong in the code you added, but perhaps a few suggestions will help:

  1. Is your isDisappearing variable an instance variable of your view controller, a global variable, or what? If it's an instance variable, figure out how it's being changed. If it's a global variable, well... don't do that.

  2. Be sure that you're heeding the warning in the docs to the effect that -textViewShouldEndEditing: is only advisory, and that the view may stop editing no matter what you return.

  3. Try temporarily removing the iToast stuff. If the crash still happens, at least you've eliminated that as a source of problems. If it stops happening, you'll have narrowed your search.

  4. Identify the cause of the crash. (This should really be first on the list.) Crashes don't just happen mysteriously -- there's a reason that it happens. Find that reason, and you're 85% done. Start by examining the stack trace when the crash occurs. If that doesn't provide enough clues, place a breakpoint somewhere before the line that causes the crash and start stepping until you crash. If all else fails, start logging messages to trace execution and monitor your assumptions.

  5. What exactly is your view controller A doing in its -viewWillAppear method? Could that be part of the problem? Could you move that code to, say, -viewDidAppear instead?

Edit app in order to support both IOS 7 and 8

Changing deployment target will not work.
Please keep deployment target to the lowest supported iOS version.

Also, Apple provides backward compatibility. So the deprecated methods will work.
For best result use respondsToSelector .

Try to replace deprecated methods but with caution. Keep your old methods as is. And conditionally give support for iOS 8 and above.

Hope i am helpful.
Thanks

Is there a quick way to fold and unfold comments in xcode 7?

Code-folding block comments does not work in Xcode 7 - 7.2.1 in Swift files.

You can, however, hack it by using an empty closure to surround the comments. This will also work with multiple line comments too.

_ = { /* Comment
myCommented.code
*/ }

Definitely a hack, but could save you lots of scrolling around.

Is there a change in the processing of the order of events in iOS 8.1 and xCode 6

Don't ever assume that the order of internal Apple events in the runloop will be in order, especially when they are related to independent objects.

In this case you have the UITextField delegate method firing, and the UIButton touch. Don't link the two in your code. If you need the data to be saved before the email is sent, please make sure that the data is indeed saved before the email is sent.

One way to do it is to have a bool like dataIsModified that you set to true whenever any data is modified, and reset when the save is done. Then in the email sending method, check if dataIsModified, then save again.

NSObject +load and +initialize - What do they do?

The load message

The runtime sends the load message to each class object, very soon after the class object is loaded in the process's address space. For classes that are part of the program's executable file, the runtime sends the load message very early in the process's lifetime. For classes that are in a shared (dynamically-loaded) library, the runtime sends the load message just after the shared library is loaded into the process's address space.

Furthermore, the runtime only sends load to a class object if that class object itself implements the load method. Example:

@interface Superclass : NSObject
@end

@interface Subclass : Superclass
@end

@implementation Superclass

+ (void)load {
NSLog(@"in Superclass load");
}

@end

@implementation Subclass

// ... load not implemented in this class

@end

The runtime sends the load message to the Superclass class object. It does not send the load message to the Subclass class object, even though Subclass inherits the method from Superclass.

The runtime sends the load message to a class object after it has sent the load message to all of the class's superclass objects (if those superclass objects implement load) and all of the class objects in shared libraries you link to. But you don't know which other classes in your own executable have received load yet.

Every class that your process loads into its address space will receive a load message, if it implements the load method, regardless of whether your process makes any other use of the class.

You can see how the runtime looks up the load method as a special case in the _class_getLoadMethod of objc-runtime-new.mm, and calls it directly from call_class_loads in objc-loadmethod.mm.

The runtime also runs the load method of every category it loads, even if several categories on the same class implement load.  This is unusual.  Normally, if two categories define the same method on the same class, one of the methods will “win” and be used, and the other method will never be called.

The initialize Method

The runtime calls the initialize method on a class object just before sending the first message (other than load or initialize) to the class object or any instances of the class. This message is sent using the normal mechanism, so if your class doesn't implement initialize, but inherits from a class that does, then your class will use its superclass's initialize. The runtime will send the initialize to all of a class's superclasses first (if the superclasses haven't already been sent initialize).

Example:

@interface Superclass : NSObject
@end

@interface Subclass : Superclass
@end

@implementation Superclass

+ (void)initialize {
NSLog(@"in Superclass initialize; self = %@", self);
}

@end

@implementation Subclass

// ... initialize not implemented in this class

@end

int main(int argc, char *argv[]) {
@autoreleasepool {
Subclass *object = [[Subclass alloc] init];
}
return 0;
}

This program prints two lines of output:

2012-11-10 16:18:38.984 testApp[7498:c07] in Superclass initialize; self = Superclass
2012-11-10 16:18:38.987 testApp[7498:c07] in Superclass initialize; self = Subclass

Since the system sends the initialize method lazily, a class won't receive the message unless your program actually sends messages to the class (or a subclass, or instances of the class or subclasses). And by the time you receive initialize, every class in your process should have already received load (if appropriate).

The canonical way to implement initialize is this:

@implementation Someclass

+ (void)initialize {
if (self == [Someclass class]) {
// do whatever
}
}

The point of this pattern is to avoid Someclass re-initializing itself when it has a subclass that doesn't implement initialize.

The runtime sends the initialize message in the _class_initialize function in objc-initialize.mm. You can see that it uses objc_msgSend to send it, which is the normal message-sending function.

Further reading

Check out Mike Ash's Friday Q&A on this topic.

How to re-order segues in initial view's tabbar controller in xcode 4.5?

The positions in each view are associated with the positions on the bottom bar of the Tab Bar Controller. If you reorder that bar you will reorder your views. You can reorder them by drag and drop on your interface builder.

In your example just select Home in your Tab Bar Controller and drag it to the first position.

If you have problems dragging and dropping try to select first your Tab View Controller or exit your XCode and open it again (like @thepumpkin1979 and @Rick pointed out).



Related Topics



Leave a reply



Submit